diff --git a/Controller/UpdateController.php b/Controller/UpdateController.php
index b44662b..f8d3aaf 100644
--- a/Controller/UpdateController.php
+++ b/Controller/UpdateController.php
@@ -6,6 +6,7 @@ error_reporting(error_level: E_ALL);
 
 use DirectoryIterator;
 use Exception;
+use JetBrains\PhpStorm\NoReturn;
 use PDO;
 use PharData;
 
@@ -18,504 +19,561 @@ const SUPPORTED_RELEASE_MINOR = 2;
  */
 class UpdateController
 {
-	function handleUpdate(): void
-	{
-		define(constant_name: "PHPBB_ROOT_PATH", value: dirname(path: __DIR__, levels: 2));
-		
-		$phpBBRootPath = PHPBB_ROOT_PATH . '/';
-		$phpEx = substr(string: strrchr(haystack: __FILE__, needle: '.'), offset: 1);
-		
-		
-		// sanity checks
-		
-		if (strtoupper(string: substr(string: PHP_OS, offset: 0, length: 3)) === 'WIN') {
-			echo 'This program must not be used on Windows installations.' . PHP_EOL;
-			exit(1);
-		}
-		
-		if (PHP_VERSION_ID < 80100) {
-			echo 'You need at least php version 8.1.0';
-			exit(1);
-		}
-		
-		if (php_sapi_name() !== 'cli') {
-			echo 'This program must be run from the command line.' . PHP_EOL;
-			exit(1);
-		}
-		
-		if (!extension_loaded(extension: 'bz2')) {
-			echo 'You need to install/enable the bz2 PHP extension' . PHP_EOL;
-			exit(1);
-		}
-		
-		include $phpBBRootPath . 'config.php';
-		
-		/** @var String $dbhost */
-		/** @var String $dbport */
-		/** @var String $dbname */
-		/** @var String $dbuser */
-		/** @var String $dbpasswd */
-		$pdo = new PDO(
-			dsn     : "mysql:host=$dbhost;port=$dbport;charset=utf8mb4;dbname=$dbname",
-			username: $dbuser,
-			password: $dbpasswd
-		);
-		
-		
-		/** @var String $table_prefix */
-		$sql = "SELECT config_value FROM ${table_prefix}config WHERE config_name = 'version'";
-		$statement = $pdo->prepare(query: $sql);
-		$statement->execute();
-		$result = $statement->fetch();
-		
-		$installedVersion = $result['config_value'];
-		print("Installed version: phpBB $installedVersion" . PHP_EOL);
-		
-		// phpBB has major, minor and maintenance version scheme
-		[$major, $minor, $patch] = explode(separator: '.', string: $installedVersion);
-		if ((intval(value: $major) != SUPPORTED_RELEASE_MAJOR) || (intval(value: $minor) < SUPPORTED_RELEASE_MINOR)) {
-			echo 'This script only supports phpBB ' . SUPPORTED_RELEASE_MAJOR . '.' . SUPPORTED_RELEASE_MINOR . ' and above branch.', PHP_EOL;
-			exit(1);
-		}
-		
-		$json = file_get_contents(filename: 'https://version.phpbb.com/phpbb/versions.json');
-		$versions = json_decode(json: $json);
-		
-		$stableVersions = $versions->stable;
-		$availableUpdate = $stableVersions->{$major . '.' . $minor}->{'current'};
-		
-		echo 'Current Version: ' . $availableUpdate . PHP_EOL;
-		
-		// check for existing update
-		if (!file_exists(filename: 'dist')) {
-			echo "'dist' folder is missing, create a new one …'";
-			mkdir(directory: 'dist');
-		}
-		
-		$currentFile = "phpBB-$availableUpdate.tar.bz2";
-		
-		$phpBBTarget = "dist/$currentFile";
-		
-		if (!file_exists(filename: $phpBBTarget)) {
-			echo "Downloading $currentFile" . PHP_EOL;
-			$filePath = "https://download.phpbb.com/pub/release/$major.$minor/$availableUpdate/$currentFile";
-			$phpBBtbz = file_get_contents(filename: $filePath);
-			file_put_contents(filename: $phpBBTarget, data: $phpBBtbz);
-		} else {
-			echo $currentFile . ' already exists' . PHP_EOL;
-		}
-		
-		// TODO check SHA256?
-		
-		// check for available language files
-		
-		$useLangDeDu = false;
-		if (file_exists(filename: $phpBBRootPath . 'language/de')) {
-			$useLangDeDu = true;
-			$languageFile = "phpBB_lang_de-$availableUpdate.tar.bz2";
-			$langDeDuTarget = "dist/$languageFile";
-			
-			if (!file_exists(filename: $langDeDuTarget)) {
-				echo "Downloading language $languageFile" . PHP_EOL;
-				$filePath = "https://downloads.phpbb.de/pakete/deutsch/$major.$minor/$availableUpdate/$languageFile";
-				if (file_exists(filename: $filePath)) {
-					$phpBBtbz = file_get_contents(filename: $filePath);
-					file_put_contents(filename: $langDeDuTarget, data: $phpBBtbz);
-				} else {
-					echo "Language file $languageFile does not exist." . PHP_EOL;
-					$useLangDeDu = false;
-				}
-			} else {
-				echo 'Language file ' . $languageFile . ' already exists' . PHP_EOL;
-			}
-		} else {
-			echo 'Language Deutsch "Du" ist not installed, skipping' . PHP_EOL;
-		}
-		
-		$useLangDeSie = false;
-		if (file_exists(filename: $phpBBRootPath . 'language/de_x_sie')) {
-			$useLangDeSie = true;
-			$languageFile = "phpBB_lang_de_x_sie-$availableUpdate.tar.bz2";
-			$langDeSieTarget = "dist/$languageFile";
-			
-			if (!file_exists(filename: $langDeSieTarget)) {
-				echo "Downloading language $languageFile" . PHP_EOL;
-				$filePath = "https://downloads.phpbb.de/pakete/deutsch/$major.$minor/$availableUpdate/$languageFile";
-				if (file_exists(filename: $filePath)) {
-					$phpBBtbz = file_get_contents(filename: $filePath);
-					file_put_contents(filename: $langDeSieTarget, data: $phpBBtbz);
-				} else {
-					echo 'Language file ' . $languageFile . ' does not exist' . PHP_EOL;
-					$useLangDeSie = false;
-				}
-			} else {
-				echo 'Language file ' . $languageFile . ' already exists' . PHP_EOL;
-			}
-		} else {
-			echo 'Language Deutsch "Sie" ist not installed, skipping' . PHP_EOL;
-		}
-		
-		if (!$this->confirm(message: 'Do you want to proceed with the update now?')) {
-			exit(0);
-		}
-		
-		// ok, start update
-		$now = date(format: 'd.m.Y H:i');
-		$disableMsg = "Software-update at $now, the forum ist down due to maintenance. We'll be back soon.";
-		$sql = "UPDATE ${table_prefix}config SET config_value = :disable_message WHERE config_name = 'board_disable_msg'";
-		$statement = $pdo->prepare(query: $sql);
-		$statement->bindParam(param: 'disable_message', var: $disableMsg);
-		
-		if ($statement->execute()) {
-			echo "Disable Message set …", PHP_EOL;
-		} else {
-			echo 'There was an error talking to the DB.' . PHP_EOL;
-			echo 'Failed SQL-statement: ' . $sql . PHP_EOL;
-			exit(1);
-		}
-		
-		$sql = "UPDATE ${table_prefix}config SET config_value = '1' WHERE config_name = 'board_disable'";
-		$statement = $pdo->prepare(query: $sql);
-		if ($statement->execute()) {
-			echo "Board disabled …", PHP_EOL;
-		} else {
-			echo 'There was an error talking to the DB.' . PHP_EOL;
-			echo 'Failed SQL-statement: ' . $sql . PHP_EOL;
-			exit(1);
-		}
-		
-		$extensionsFile = 'extensions.txt';
-		
-		if (file_exists(filename: $extensionsFile)) {
-			echo 'Extensions state already stored. Remove extensions.txt if you wish to recreate it.' . PHP_EOL;
-		} else {
-			// check for enabled extensions
-			$sql = "SELECT ext_name FROM ${table_prefix}ext WHERE ext_active = '1'";
-			$statement = $pdo->prepare(query: $sql);
-			if ($statement->execute()) {
-				$result = $statement->fetchAll();
-				
-				if (count(value: $result) > 0) {
-					$extensions = json_encode(value: $result);
-					
-					// safe enabled extensions
-					$oFile = fopen(filename: 'extensions.txt', mode: 'w');
-					fputs(stream: $oFile, data: $extensions);
-					fclose(stream: $oFile);
-					echo 'Stored extensions state';
-					
-					// disable all extensions
-					$sql = "UPDATE ${table_prefix}ext SET ext_active = '0' WHERE ext_active = '1'";
-					$statement = $pdo->prepare(query: $sql);
-					if ($statement->execute()) {
-						echo 'Disabled all extensions';
-					}
-				}
-				
-			}
-		}
-		
-		$stylesFile =  'styles.txt';
-		if (file_exists(filename: $stylesFile)) {
-			echo 'Styles state already stored. Remove styles.txt if you wish to recreate it' . PHP_EOL;
-		} else {
-			// check for enabled style
-			$sql = "SELECT style_name FROM ${table_prefix}styles WHERE style_active = '1'";
-			$statement = $pdo->prepare(query: $sql);
-			if ($statement->execute()) {
-				$result = $statement->fetchAll();
-				
-				if (count(value: $result) > 0) {
-					$styles = json_encode(value: $result);
-					
-					// safe enabled styles
-					$oFile = fopen(filename: 'styles.txt', mode: 'w');
-					fputs(stream: $oFile, data: $styles);
-					fclose(stream: $oFile);
-					echo 'Stored styles state.' . PHP_EOL;
-					
-					// disable all styles except prosilver
-					$sql = "UPDATE ${table_prefix}styles SET style_active = '0' WHERE NOT style_name = 'prosilver'";
-					$statement = $pdo->prepare(query: $sql);
-					if ($statement->execute()) {
-						echo 'Disabled all styles except prosilver.' . PHP_EOL;
-					}
-				}
-				
-			}
-		}
-		
-		// update phpBB
-		$data = new PharData(filename: $phpBBTarget);
-		try {
-			unset($data['phpBB3/config.php']);
-			unset($data['phpBB3/.htaccess']);
-		} catch (Exception $e) {
-			echo 'error: ', $e;
-		}
-		
-		// remove all old files
-		$excludes = [
-			'config.php',
-			'.htaccess',
-			'.htpasswd',
-			'images',
-			'files',
-			'ext',
-			'styles',
-			'store',
-			'updates',
-			'mobiquo'];
-		// this will fuck up nearly all modified boards, leave the files alone by default.
-		// It will also destroy any API-keys and whatever you might have in your document root.
-		//         deleteDirectory($phpbb_root_path, $excludes);
-		
-		
-		try {
-			$data->extractTo(directory: $phpBBRootPath);
-			
-			$fromDir = $phpBBRootPath . 'phpBB3/';
-			$toDir = $phpBBRootPath;
-			
-			$this->copyDirectory(source: $fromDir, target: $toDir);
-			$this->deleteDirectory(dir: $fromDir);
-		} catch (Exception $e) {
-			print("Error while extracting $data: $e");
-			exit(1);
-		}
-		echo 'Moved the update in place.', PHP_EOL;
-		
-		$fileOwner = fileowner(filename: $phpBBRootPath);
-		$fileGroup = filegroup(filename: $phpBBRootPath);
-		$fileOwnerName = posix_getpwuid(user_id: $fileOwner)['name'];
-		$fileGroupName = posix_getgrgid(group_id: $fileGroup)['name'];
-		
-		
-		echo 'Check file owner', PHP_EOL;
-		print("You might need to perform 'chown -R $fileOwnerName:$fileGroupName $phpBBRootPath'" . PHP_EOL);
-		
-		echo 'prepare config.yml.', PHP_EOL;
-		$oFile = fopen(filename: $phpBBRootPath . '/update-config.yml', mode: 'w');
-		fputs(stream: $oFile, data: 'updater:' . PHP_EOL . "        type: db_only" . PHP_EOL);
-		fclose(stream: $oFile);
-		
-		$command = <<<EOC
+    /**
+     * @var true
+     */
+    private bool $dryRun = false;
+    private string $installedVersion = '';
+
+    function parseOpts(): array
+    {
+        $shortOpts = 'h::d::';
+
+        $longOpts = [
+                'help',
+                'dry-run',
+        ];
+
+        return getopt(
+                short_options: $shortOpts,
+                long_options: $longOpts
+        );
+    }
+
+    #[NoReturn]
+    function handleUpdate(): void
+    {
+        define(constant_name: "PHPBB_ROOT_PATH", value: dirname(path: __DIR__, levels: 2));
+
+        $phpBBRootPath = PHPBB_ROOT_PATH . '/';
+        $phpEx = substr(string: strrchr(haystack: __FILE__, needle: '.'), offset: 1);
+
+
+        // sanity checks
+
+        if (strtoupper(string: substr(string: PHP_OS, offset: 0, length: 3)) === 'WIN') {
+            echo 'This program must not be used on Windows installations.' . PHP_EOL;
+            exit(1);
+        }
+
+        if (PHP_VERSION_ID < 80100) {
+            echo 'You need at least php version 8.1.0';
+            exit(1);
+        }
+
+        if (php_sapi_name() !== 'cli') {
+            echo 'This program must be run from the command line.' . PHP_EOL;
+            exit(1);
+        }
+
+        if (!extension_loaded(extension: 'bz2')) {
+            echo 'You need to install/enable the bz2 PHP extension' . PHP_EOL;
+            exit(1);
+        }
+
+        if (!$this->dryRun) {
+            include $phpBBRootPath . 'config.php';
+
+            /** @var String $dbhost */
+            /** @var String $dbport */
+            /** @var String $dbname */
+            /** @var String $dbuser */
+            /** @var String $dbpasswd */
+            $pdo = new PDO(
+                    dsn: "mysql:host=$dbhost;port=$dbport;charset=utf8mb4;dbname=$dbname",
+                    username: $dbuser,
+                    password: $dbpasswd
+            );
+
+
+            /** @var String $table_prefix */
+            $sql = "SELECT config_value FROM {$table_prefix}config WHERE config_name = 'version'";
+            $statement = $pdo->prepare(query: $sql);
+            $statement->execute();
+            $result = $statement->fetch();
+
+            $installedVersion = $result['config_value'];
+            print("Installed version: phpBB $installedVersion" . PHP_EOL);
+
+            // phpBB has major, minor and maintenance version scheme
+            [$major, $minor, $patch] = explode(separator: '.', string: $installedVersion);
+            if ((intval(value: $major) != SUPPORTED_RELEASE_MAJOR) || (intval(value: $minor) < SUPPORTED_RELEASE_MINOR)) {
+                echo 'This script only supports phpBB ' . SUPPORTED_RELEASE_MAJOR . '.' . SUPPORTED_RELEASE_MINOR . ' and above branch.', PHP_EOL;
+                exit(1);
+            }
+        }
+
+        echo "Checking for the current version …" . PHP_EOL;
+        $json = file_get_contents(filename: 'https://version.phpbb.com/phpbb/versions.json');
+        $versions = json_decode(json: $json, associative: true);
+
+        $stableVersions = $versions['stable'];
+
+        // Get the highest stable version
+        $highestStableVersion = null;
+        foreach ($stableVersions as $version => $details) {
+            if ($highestStableVersion === null || version_compare(version1: $version, version2: $highestStableVersion, operator: '>')) {
+                $highestStableVersion = $version;
+            }
+        }
+
+        echo "Highest Stable Version: $highestStableVersion" . PHP_EOL;
+        if (!$this->dryRun) {
+            echo "Installed Version: $installedVersion" . PHP_EOL;
+        }
+
+        [$major, $minor, $patch] = explode(separator: '.', string: $stableVersions[$highestStableVersion]['current']);
+        echo "Latest stable release: $major.$minor.$patch" . PHP_EOL;
+        $availableUpdate = $stableVersions[$highestStableVersion]['current'];
+        // check for existing update
+        if (!file_exists(filename: 'dist')) {
+            echo "'dist' folder is missing, create a new one …'";
+            mkdir(directory: 'dist');
+        }
+
+        $currentFile = "phpBB-$availableUpdate.tar.bz2";
+
+        $phpBBTarget = "dist/$currentFile";
+
+        if (!file_exists(filename: $phpBBTarget)) {
+            echo "Downloading $currentFile" . PHP_EOL;
+            $filePath = "https://download.phpbb.com/pub/release/$major.$minor/$availableUpdate/$currentFile";
+            $phpBBtbz = file_get_contents(filename: $filePath);
+            file_put_contents(filename: $phpBBTarget, data: $phpBBtbz);
+        } else {
+            echo $currentFile . ' already exists. Skipping download.' . PHP_EOL;
+        }
+
+        // TODO check SHA256?
+
+        // check for available language files
+
+        $useLangDeDu = false;
+        if (file_exists(filename: $phpBBRootPath . 'language/de')) {
+            $useLangDeDu = true;
+            // https://downloads.phpbb.de/pakete/deutsch/3.3/3.3.10/phpBB_lang_de-3.3.10.tar.bz2
+            $languageFile = "phpBB_lang_de-$availableUpdate.tar.bz2";
+            echo "language file: $languageFile";
+            $langDeDuTarget = "dist/$languageFile";
+
+            if (!file_exists(filename: $langDeDuTarget)) {
+                echo "Downloading language $languageFile" . PHP_EOL;
+                $filePath = "https://downloads.phpbb.de/pakete/deutsch/$major.$minor/$availableUpdate/$languageFile";
+                if (file_exists(filename: $filePath)) {
+                    $phpBBtbz = file_get_contents(filename: $filePath);
+                    file_put_contents(filename: $langDeDuTarget, data: $phpBBtbz);
+                } else {
+                    echo "Language file $languageFile does not exist." . PHP_EOL;
+                    $useLangDeDu = false;
+                }
+            } else {
+                echo 'Language file ' . $languageFile . ' already exists' . PHP_EOL;
+            }
+        } else {
+            echo 'Language Deutsch "Du" ist not installed, skipping' . PHP_EOL;
+        }
+
+        $useLangDeSie = false;
+        if (file_exists(filename: $phpBBRootPath . 'language/de_x_sie')) {
+            $useLangDeSie = true;
+            $languageFile = "phpBB_lang_de_x_sie-$availableUpdate.tar.bz2";
+            $langDeSieTarget = "dist/$languageFile";
+
+            if (!file_exists(filename: $langDeSieTarget)) {
+                echo "Downloading language $languageFile" . PHP_EOL;
+                $filePath = "https://downloads.phpbb.de/pakete/deutsch/$major.$minor/$availableUpdate/$languageFile";
+                if (file_exists(filename: $filePath)) {
+                    $phpBBtbz = file_get_contents(filename: $filePath);
+                    file_put_contents(filename: $langDeSieTarget, data: $phpBBtbz);
+                } else {
+                    echo 'Language file ' . $languageFile . ' does not exist' . PHP_EOL;
+                    $useLangDeSie = false;
+                }
+            } else {
+                echo 'Language file ' . $languageFile . ' already exists' . PHP_EOL;
+            }
+        } else {
+            echo 'Language Deutsch "Sie" ist not installed, skipping' . PHP_EOL;
+        }
+
+        if (!$this->confirm(message: 'Do you want to proceed with the update now?')) {
+            exit(0);
+        }
+
+        if ($this->dryRun) {
+            echo 'Dry run, exiting.' . PHP_EOL;
+            exit(0);
+        }
+
+        // ok, start update
+        $now = date(format: 'd.m.Y H:i');
+        $disableMsg = "Software-update at $now, the forum ist down due to maintenance. We'll be back soon.";
+        $sql = "UPDATE {$table_prefix}config SET config_value = :disable_message WHERE config_name = 'board_disable_msg'";
+        $statement = $pdo->prepare(query: $sql);
+        $statement->bindParam(param: 'disable_message', var: $disableMsg);
+
+        if ($statement->execute()) {
+            echo "Disable Message set …", PHP_EOL;
+        } else {
+            echo 'There was an error talking to the DB.' . PHP_EOL;
+            echo 'Failed SQL-statement: ' . $sql . PHP_EOL;
+            exit(1);
+        }
+
+        $sql = "UPDATE {$table_prefix}config SET config_value = '1' WHERE config_name = 'board_disable'";
+        $statement = $pdo->prepare(query: $sql);
+        if ($statement->execute()) {
+            echo "Board disabled …", PHP_EOL;
+        } else {
+            echo 'There was an error talking to the DB.' . PHP_EOL;
+            echo 'Failed SQL-statement: ' . $sql . PHP_EOL;
+            exit(1);
+        }
+
+        $extensionsFile = 'extensions.txt';
+
+        if (file_exists(filename: $extensionsFile)) {
+            echo 'Extensions state already stored. Remove extensions.txt if you wish to recreate it.' . PHP_EOL;
+        } else {
+            // check for enabled extensions
+            $sql = "SELECT ext_name FROM {$table_prefix}ext WHERE ext_active = '1'";
+            $statement = $pdo->prepare(query: $sql);
+            if ($statement->execute()) {
+                $result = $statement->fetchAll();
+
+                if (count(value: $result) > 0) {
+                    $extensions = json_encode(value: $result);
+
+                    // safe enabled extensions
+                    $oFile = fopen(filename: 'extensions.txt', mode: 'w');
+                    fputs(stream: $oFile, data: $extensions);
+                    fclose(stream: $oFile);
+                    echo 'Stored extensions state';
+
+                    // disable all extensions
+                    $sql = "UPDATE {$table_prefix}ext SET ext_active = '0' WHERE ext_active = '1'";
+                    $statement = $pdo->prepare(query: $sql);
+                    if ($statement->execute()) {
+                        echo 'Disabled all extensions';
+                    }
+                }
+
+            }
+        }
+
+        $stylesFile = 'styles.txt';
+        if (file_exists(filename: $stylesFile)) {
+            echo 'Styles state already stored. Remove styles.txt if you wish to recreate it' . PHP_EOL;
+        } else {
+            // check for enabled style
+            $sql = "SELECT style_name FROM {$table_prefix}styles WHERE style_active = '1'";
+            $statement = $pdo->prepare(query: $sql);
+            if ($statement->execute()) {
+                $result = $statement->fetchAll();
+
+                if (count(value: $result) > 0) {
+                    $styles = json_encode(value: $result);
+
+                    // safe enabled styles
+                    $oFile = fopen(filename: 'styles.txt', mode: 'w');
+                    fputs(stream: $oFile, data: $styles);
+                    fclose(stream: $oFile);
+                    echo 'Stored styles state.' . PHP_EOL;
+
+                    // disable all styles except prosilver
+                    $sql = "UPDATE {$table_prefix}styles SET style_active = '0' WHERE NOT style_name = 'prosilver'";
+                    $statement = $pdo->prepare(query: $sql);
+                    if ($statement->execute()) {
+                        echo 'Disabled all styles except prosilver.' . PHP_EOL;
+                    }
+                }
+
+            }
+        }
+
+        // update phpBB
+        $data = new PharData(filename: $phpBBTarget);
+        try {
+            unset($data['phpBB3/config.php']);
+            unset($data['phpBB3/.htaccess']);
+        } catch (Exception $e) {
+            echo 'error: ', $e;
+        }
+
+        // remove all old files
+        $excludes = [
+                'config.php',
+                '.htaccess',
+                '.htpasswd',
+                'images',
+                'files',
+                'ext',
+                'styles',
+                'store',
+                'updates',
+                'mobiquo'];
+        // this will fuck up nearly all modified boards, leave the files alone by default.
+        // It will also destroy any API-keys and whatever you might have in your document root.
+        //         deleteDirectory($phpbb_root_path, $excludes);
+
+
+        try {
+            $data->extractTo(directory: $phpBBRootPath);
+
+            $fromDir = $phpBBRootPath . 'phpBB3/';
+            $toDir = $phpBBRootPath;
+
+            $this->copyDirectory(source: $fromDir, target: $toDir);
+            $this->deleteDirectory(dir: $fromDir);
+        } catch (Exception $e) {
+            print("Error while extracting $data: $e");
+            exit(1);
+        }
+        echo 'Moved the update in place.', PHP_EOL;
+
+        $fileOwner = fileowner(filename: $phpBBRootPath);
+        $fileGroup = filegroup(filename: $phpBBRootPath);
+        $fileOwnerName = posix_getpwuid(user_id: $fileOwner)['name'];
+        $fileGroupName = posix_getgrgid(group_id: $fileGroup)['name'];
+
+
+        echo 'Check file owner', PHP_EOL;
+        print("You might need to perform 'chown -R $fileOwnerName:$fileGroupName $phpBBRootPath'" . PHP_EOL);
+
+        echo 'prepare config.yml.', PHP_EOL;
+        $oFile = fopen(filename: $phpBBRootPath . '/update-config.yml', mode: 'w');
+        fputs(stream: $oFile, data: 'updater:' . PHP_EOL . "        type: db_only" . PHP_EOL);
+        fclose(stream: $oFile);
+
+        $command = <<<EOC
 		cd ..
 		php install/phpbbcli.php update update-config.yml
 		EOC;
-		
-		system(command: $command, result_code: $resultCode);
-		
-		if ($resultCode != 0) {
-			echo 'There was an error updating the database: ' . $resultCode . PHP_EOL;
-			exit(1);
-		} else {
-			echo 'The database has been updated' . PHP_EOL;
-		}
-		
-		$installDir = $phpBBRootPath . '/install';
-		if (is_dir(filename: $installDir)) {
-			$this->deleteDirectory(dir: $installDir);
-		}
-		
-		
-		// update langDeDu
-		if ($useLangDeDu) {
-			$data = new PharData(filename: $langDeDuTarget);
-			
-			try {
-				$data->extractTo(directory: $phpBBRootPath, overwrite: true);
-			} catch (Exception $e) {
-				print("Error while extracting $langDeDuTarget: $e");
-				exit(1);
-			}
-		}
-		
-		
-		// update langDeSie
-		if ($useLangDeSie) {
-			$data = new PharData(filename: $langDeSieTarget);
-			
-			try {
-				$data->extractTo(directory: $phpBBRootPath, overwrite: true);
-			} catch (Exception $e) {
-				print("Error while extracting $langDeSieTarget: $e");
-				exit(1);
-			}
-		}
-		
-		
-		
-		$sql = "UPDATE ${table_prefix}config SET config_value = '0' WHERE config_name = 'board_disable'";
-		$statement = $pdo->prepare(query: $sql);
-		$statement->execute();
-		
-		echo "Board reenabled …", PHP_EOL;
-		
-		
-		if (file_exists(filename: $extensionsFile)) {
-			$iFile = fopen(filename: $extensionsFile, mode: 'r');
-			$extensions = json_decode(json: fgets(stream: $iFile), associative: true);
-			
-			echo 'Enable extensions: ';
-			
-			foreach ($extensions as $extension) {
-				$ext = $extension['ext_name'];
-				$sql = "UPDATE ${table_prefix}ext SET ext_active = '1' WHERE ext_name = '$ext'";
-				$statement = $pdo->prepare(query: $sql);
-				$statement->execute();
-				echo '.';
-			}
-			echo 'done.', PHP_EOL;
-		} else {
-			echo 'There are no saved extension information available.', PHP_EOL;
-		}
-		
-		if (file_exists(filename: $stylesFile)) {
-			$iFile = fopen(filename: $stylesFile, mode: 'r');
-			$styles = json_decode(json: fgets(stream: $iFile), associative: true);
-			
-			echo 'Enable styles: ';
-			
-			foreach ($styles as $style) {
-				$style = $style['style_name'];
-				$sql = "UPDATE ${table_prefix}styles SET style_active = '1' WHERE style_name = '$style'";
-				$statement = $pdo->prepare(query: $sql);
-				$statement->execute();
-				echo '.';
-			}
-			echo 'done.', PHP_EOL;
-		} else {
-			echo 'There are no saved extension information available.', PHP_EOL;
-		}
+
+        system(command: $command, result_code: $resultCode);
+
+        if ($resultCode != 0) {
+            echo 'There was an error updating the database: ' . $resultCode . PHP_EOL;
+            exit(1);
+        } else {
+            echo 'The database has been updated' . PHP_EOL;
+        }
+
+        $installDir = $phpBBRootPath . '/install';
+        if (is_dir(filename: $installDir)) {
+            $this->deleteDirectory(dir: $installDir);
+        }
 
 
-		// clear cache
-		$dataGlobalCache = $phpBBRootPath . '/cache/data_global.' . $phpEx;
-		
-		if (file_exists(filename: $dataGlobalCache)) {
-			unlink(filename: $dataGlobalCache);
-			echo "Cache cleared …";
-		}
-		
-		echo "Your board should now be up and running." . PHP_EOL;
-	}
-	
-	
-	/**
-	 * @param String   $message
-	 * @param string[] $options
-	 * @param string   $default
-	 *
-	 * @return bool
-	 */
-	function confirm(string $message = 'Are you sure? ', array $options = ['y', 'n'], string $default = 'n'): bool
-	{
-		// first $options means true, any other false
-		
-		echo $message, ' (';
-		$first = true;
-		foreach ($options as $option) {
-			// mark default
-			if ($option == $default) {
-				$option = strtoupper(string: $option);
-			}
-			if ($first) {
-				echo $option;
-				$first = false;
-			} else {
-				echo '/', $option;
-			}
-		}
-		echo '): ';
-		
-		$handle = fopen(filename: "php://stdin", mode: 'r');
-		$line = trim(string: fgetc(stream: $handle));
-		fclose(stream: $handle);
-		
-		if ($line == '') {
-			// enter
-			$line = $default;
-		}
-		
-		if ($line == $options[0]) {
-			$result = true;
-		} else {
-			$result = false;
-		}
-		
-		return $result;
-	}
-	
-	
-	/**
-	 * @param       $dir
-	 * @param array $excludes
-	 *
-	 * @return false|void
-	 */
-	function deleteDirectory($dir, array $excludes = [])
-	{
-		if (!file_exists(filename: $dir)) {
-			return false;
-		}
-		$dir = rtrim(string: $dir, characters: '/') . '/';
-		static $skip = false;
-		
-		$entries = glob(pattern: $dir . '{,.}[!.,!..]*', flags: GLOB_MARK | GLOB_BRACE);
-		
-		foreach ($entries as $entry) {
-			if (!in_array(needle: basename(path: $entry), haystack: $excludes)) {
-				if (is_dir(filename: $entry)) {
-					$this->deleteDirectory(dir: $entry);
-				} else {
-					unlink(filename: $entry);
-				}
-			} else {
-				$skip = true;
-			}
-		}
-		if (!$skip) {
-			rmdir(directory: $dir);
-		}
-	}
-	
-	
-	/**
-	 * @param $source
-	 * @param $target
-	 *
-	 * @return bool|void
-	 */
-	function copyDirectory($source, $target)
-	{
-		if (!file_exists(filename: $source)) {
-			die("missing source: $source");
-		}
-		
-		if (is_file(filename: $source)) {
-			if (copy(from: $source, to: $target)) {
-				return true;
-			} else {
-				return false;
-			}
-		}
-		
-		if (is_dir(filename: $source)) {
-			if (!file_exists(filename: $target)) {
-				mkdir(directory: $target);
-			}
-			$source = rtrim(string: $source, characters: '/') . '/';
-			$target = rtrim(string: $target, characters: '/') . '/';
-			$dir = new DirectoryIterator(directory: $source);
-			
-			foreach ($dir as $entry) {
-				if (!$entry->isDot()) {
-					$this->copyDirectory(source: "$source$entry", target: "$target$entry");
-				}
-			}
-		}
-		// ignore links, not part of phpBB arch
-	}
-	
+        // update langDeDu
+        if ($useLangDeDu) {
+            $data = new PharData(filename: $langDeDuTarget);
+
+            try {
+                $data->extractTo(directory: $phpBBRootPath, overwrite: true);
+            } catch (Exception $e) {
+                print("Error while extracting $langDeDuTarget: $e");
+                exit(1);
+            }
+        }
+
+
+        // update langDeSie
+        if ($useLangDeSie) {
+            $data = new PharData(filename: $langDeSieTarget);
+
+            try {
+                $data->extractTo(directory: $phpBBRootPath, overwrite: true);
+            } catch (Exception $e) {
+                print("Error while extracting $langDeSieTarget: $e");
+                exit(1);
+            }
+        }
+
+
+        $sql = "UPDATE {$table_prefix}config SET config_value = '0' WHERE config_name = 'board_disable'";
+        $statement = $pdo->prepare(query: $sql);
+        $statement->execute();
+
+        echo "Board reenabled …", PHP_EOL;
+
+
+        if (file_exists(filename: $extensionsFile)) {
+            $iFile = fopen(filename: $extensionsFile, mode: 'r');
+            $extensions = json_decode(json: fgets(stream: $iFile), associative: true);
+
+            echo 'Enable extensions: ';
+
+            foreach ($extensions as $extension) {
+                $ext = $extension['ext_name'];
+                $sql = "UPDATE {$table_prefix}ext SET ext_active = '1' WHERE ext_name = '$ext'";
+                $statement = $pdo->prepare(query: $sql);
+                $statement->execute();
+                echo '.';
+            }
+            echo 'done.', PHP_EOL;
+        } else {
+            echo 'There are no saved extension information available.', PHP_EOL;
+        }
+
+        if (file_exists(filename: $stylesFile)) {
+            $iFile = fopen(filename: $stylesFile, mode: 'r');
+            $styles = json_decode(json: fgets(stream: $iFile), associative: true);
+
+            echo 'Enable styles: ';
+
+            foreach ($styles as $style) {
+                $style = $style['style_name'];
+                $sql = "UPDATE {$table_prefix}styles SET style_active = '1' WHERE style_name = '$style'";
+                $statement = $pdo->prepare(query: $sql);
+                $statement->execute();
+                echo '.';
+            }
+            echo 'done.', PHP_EOL;
+        } else {
+            echo 'There are no saved extension information available.', PHP_EOL;
+        }
+
+
+        // clear cache
+        $dataGlobalCache = $phpBBRootPath . '/cache/data_global.' . $phpEx;
+
+        if (file_exists(filename: $dataGlobalCache)) {
+            unlink(filename: $dataGlobalCache);
+            echo "Cache cleared …";
+        }
+
+        echo "Your board should now be up and running." . PHP_EOL;
+    }
+
+
+    /**
+     * @param String $message
+     * @param string[] $options
+     * @param string $default
+     *
+     * @return bool
+     */
+    function confirm(string $message = 'Are you sure? ', array $options = ['y', 'n'], string $default = 'n'): bool
+    {
+        // first $options means true, any other false
+
+        echo $message, ' (';
+        $first = true;
+        foreach ($options as $option) {
+            // mark default
+            if ($option == $default) {
+                $option = strtoupper(string: $option);
+            }
+            if ($first) {
+                echo $option;
+                $first = false;
+            } else {
+                echo '/', $option;
+            }
+        }
+        echo '): ';
+
+        $handle = fopen(filename: "php://stdin", mode: 'r');
+        $line = trim(string: fgetc(stream: $handle));
+        fclose(stream: $handle);
+
+        if ($line == '') {
+            // enter
+            $line = $default;
+        }
+
+        if ($line == $options[0]) {
+            $result = true;
+        } else {
+            $result = false;
+        }
+
+        return $result;
+    }
+
+
+    /**
+     * @param       $dir
+     * @param array $excludes
+     *
+     * @return false|void
+     */
+    function deleteDirectory($dir, array $excludes = [])
+    {
+        if (!file_exists(filename: $dir)) {
+            return false;
+        }
+        $dir = rtrim(string: $dir, characters: '/') . '/';
+        static $skip = false;
+
+        $entries = glob(pattern: $dir . '{,.}[!.,!..]*', flags: GLOB_MARK | GLOB_BRACE);
+
+        foreach ($entries as $entry) {
+            if (!in_array(needle: basename(path: $entry), haystack: $excludes)) {
+                if (is_dir(filename: $entry)) {
+                    $this->deleteDirectory(dir: $entry);
+                } else {
+                    unlink(filename: $entry);
+                }
+            } else {
+                $skip = true;
+            }
+        }
+        if (!$skip) {
+            rmdir(directory: $dir);
+        }
+    }
+
+
+    /**
+     * @param $source
+     * @param $target
+     *
+     * @return bool|void
+     */
+    function copyDirectory($source, $target)
+    {
+        if (!file_exists(filename: $source)) {
+            die("missing source: $source");
+        }
+
+        if (is_file(filename: $source)) {
+            if (copy(from: $source, to: $target)) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        if (is_dir(filename: $source)) {
+            if (!file_exists(filename: $target)) {
+                mkdir(directory: $target);
+            }
+            $source = rtrim(string: $source, characters: '/') . '/';
+            $target = rtrim(string: $target, characters: '/') . '/';
+            $dir = new DirectoryIterator(directory: $source);
+
+            foreach ($dir as $entry) {
+                if (!$entry->isDot()) {
+                    $this->copyDirectory(source: "$source$entry", target: "$target$entry");
+                }
+            }
+        }
+        // ignore links, not part of phpBB arch
+    }
+
+    public function printHelp(): void
+    {
+        echo "Usage: php update.php [options]", PHP_EOL;
+        echo "Options:", PHP_EOL;
+        echo "-h --help    Print this help", PHP_EOL;
+        echo "-d --dry-run Just check for downloadable files, don't connect to database.", PHP_EOL;
+    }
+
+    public function setDryRun(): void
+    {
+        $this->dryRun = true;
+    }
+
 }
diff --git a/README.md b/README.md
index 095e8fe..812ceeb 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Shell Script to update phpBB to current version.
 
 Usage: 
 
-Switch into you current phpBB root directory, then
+Switch into your current phpBB root directory, then
 
 `git clone https://git.24unix.net/tracer/phpbb_updates.git`
 
diff --git a/update.php b/update.php
index c6931c7..dc4f983 100755
--- a/update.php
+++ b/update.php
@@ -6,4 +6,17 @@ use App\UpdateController;
 require __DIR__ . '/vendor/autoload.php';
 
 $update = new UpdateController();
+
+$options = $update->parseOpts();
+
+// Help option
+if (array_key_exists(key: 'h', array: $options) || array_key_exists(key: 'help', array: $options)) {
+    $update->printHelp();
+    exit(0);
+}
+
+if (array_key_exists(key: 'd', array: $options) || array_key_exists(key: 'dry-run', array: $options)) {
+    $update->setDryRun();
+}
+
 $update->handleUpdate();