diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index de148dae6..08e82ab99 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -19,7 +19,7 @@ jobs: - name: Cache Composer packages id: composer-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: vendor key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} diff --git a/category_handler.php b/category_handler.php index f5cea9fa6..4d030ad29 100644 --- a/category_handler.php +++ b/category_handler.php @@ -71,7 +71,7 @@ function updateIconBlob($catId, $iconData, $iconMimeType) { if (!dbi_execute( 'DELETE FROM webcal_entry_categories WHERE cat_id = ? AND ( cat_owner = ?' - . ($is_admin ? ' OR cat_owner = "" )' : ' )'), + . ($is_admin ? ' OR cat_owner = '' )' : ' )'), [$id, $login] )) { $error = db_error(); diff --git a/composer.lock b/composer.lock index 6933602b0..ab7a81f41 100644 --- a/composer.lock +++ b/composer.lock @@ -234,25 +234,27 @@ }, { "name": "nikic/php-parser", - "version": "v4.17.1", + "version": "v5.0.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + "reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4a21235f7e56e713259a6f76bf4b5ea08502b9dc", + "reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -260,7 +262,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -284,9 +286,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.0" }, - "time": "2023-08-13T19:53:39+00:00" + "time": "2024-01-07T17:17:35+00:00" }, { "name": "phar-io/manifest", @@ -481,23 +483,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.29", + "version": "9.2.30", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -547,7 +549,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" }, "funding": [ { @@ -555,7 +557,7 @@ "type": "github" } ], - "time": "2023-09-19T04:57:46+00:00" + "time": "2023-12-22T06:47:57+00:00" }, { "name": "phpunit/php-file-iterator", @@ -800,16 +802,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.15", + "version": "9.6.16", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1" + "reference": "3767b2c56ce02d01e3491046f33466a1ae60a37f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3767b2c56ce02d01e3491046f33466a1ae60a37f", + "reference": "3767b2c56ce02d01e3491046f33466a1ae60a37f", "shasum": "" }, "require": { @@ -883,7 +885,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.16" }, "funding": [ { @@ -899,7 +901,7 @@ "type": "tidelift" } ], - "time": "2023-12-01T16:55:19+00:00" + "time": "2024-01-19T07:03:14+00:00" }, { "name": "sebastian/cli-parser", @@ -1144,20 +1146,20 @@ }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -1189,7 +1191,7 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" }, "funding": [ { @@ -1197,7 +1199,7 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { "name": "sebastian/diff", @@ -1471,20 +1473,20 @@ }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -1516,7 +1518,7 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" }, "funding": [ { @@ -1524,7 +1526,7 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2023-12-22T06:20:34+00:00" }, { "name": "sebastian/object-enumerator", @@ -2018,5 +2020,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.2.0" } diff --git a/docker/Dockerfile-php8-dev b/docker/Dockerfile-php8-dev index 7a1576408..c026f9a17 100644 --- a/docker/Dockerfile-php8-dev +++ b/docker/Dockerfile-php8-dev @@ -6,6 +6,11 @@ LABEL vendor="k5n.us" # Install mysqli extension RUN docker-php-ext-install mysqli +# Install PosgreSQL extension and dependencies +RUN apt-get update && apt-get install -y libpq-dev \ + && docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \ + && docker-php-ext-install pgsql pdo_pgsql + # Install GD extension and its dependencies RUN apt-get update && apt-get install -y \ libfreetype6-dev \ diff --git a/docker/docker-compose-php8-dev.yml b/docker/docker-compose-php8-dev.yml index 9db662a73..9586cf590 100644 --- a/docker/docker-compose-php8-dev.yml +++ b/docker/docker-compose-php8-dev.yml @@ -4,7 +4,7 @@ # docker-compose up). You only need to do this once. # # Start a shell on the mariadb container: -# docker-compose -f docker/docker-compose-php8-dev.yml exec db /bin/sh +# docker-compose -f docker/docker-compose-php8-dev.yml exec db-mariadb /bin/sh # Start the mariadb client: # /bin/mariadb -p # (enter the MYSQL_ROOT_PASSWORD below) @@ -15,15 +15,15 @@ # # If you need shell access on the webserver container running WebCalendar, you can use # the following command: -# docker-compose -f docker/docker-compose-php8-dev.yml exec webcalendar-php8 /bin/sh +# docker-compose -f docker/docker-compose-php8-dev.yml exec webcalendar-php8-mariadb /bin/sh version: '3.1' services: - db: + db-mariadb: image: mariadb - container_name: webcalendar-db + container_name: webcalendar-maria-db volumes: - mysql-data:/var/lib/mysql - /etc/localtime:/etc/localtime:ro @@ -34,12 +34,12 @@ services: - MYSQL_USER=webcalendar restart: unless-stopped - webcalendar-php8: + webcalendar-php8-mariadb: build: context: ../ dockerfile: docker/Dockerfile-php8-dev depends_on: - - db + - db-mariadb ports: - 8080:80 volumes: @@ -56,10 +56,49 @@ services: - WEBCALENDAR_DB_DATABASE=webcalendar_php8 - WEBCALENDAR_DB_LOGIN=webcalendar - WEBCALENDAR_DB_PASSWORD=Webcalendar.1 - - WEBCALENDAR_DB_HOST=db + - WEBCALENDAR_DB_HOST=db-mariadb - WEBCALENDAR_DB_PERSISTENT=true - WEBCALENDAR_USER_INC=user.php - WEBCALENDAR_MODE=dev + webcalendar-php8-pgsql: + build: + context: ../ + dockerfile: docker/Dockerfile-php8-dev + depends_on: + - db-pgsql + ports: + - 8081:80 + volumes: + - ..:/var/www/html/ + environment: + - WEBCALENDAR_USE_ENV=true + - WEBCALENDAR_INSTALL_PASSWORD=da1437a2c74ee0b35eed71e27d00c618 + - WEBCALENDAR_DB_TYPE=postgresql + - WEBCALENDAR_DB_DATABASE=webcalendar_php81 + - WEBCALENDAR_DB_LOGIN=webcalendar + - WEBCALENDAR_DB_PASSWORD=Webcalendar.1 # Change this + - WEBCALENDAR_DB_HOST=db-pgsql + - WEBCALENDAR_DB_PERSISTENT=true + - WEBCALENDAR_USER_INC=user.php + - WEBCALENDAR_MODE=dev + + # To access the pgsql command line: + # docker-compose -f docker/docker-compose-php8-dev.yml exec db-pgsql /bin/bash + # Before the webcalendar db is created: + # psql -h localhost -p 5432 -U webcalendar -W -d postgres + db-pgsql: + image: postgres + container_name: webcalendar-db-pgsql + volumes: + - pgsql-data:/var/lib/postgresql/data + - /etc/localtime:/etc/localtime:ro + environment: + - POSTGRES_DB=webcalendar_php81 + - POSTGRES_USER=webcalendar + - POSTGRES_PASSWORD=Webcalendar.1 # Change this + restart: unless-stopped + volumes: - mysql-data: + mysql-data: # MySQL/Maria data volume for persistence + pgsql-data: # PostgreSQL data volume for persistence diff --git a/edit_entry_handler.php b/edit_entry_handler.php index d0eae6339..e5bdcd6b0 100644 --- a/edit_entry_handler.php +++ b/edit_entry_handler.php @@ -714,7 +714,7 @@ function sort_byday( $a, $b ) { $cat_owner = ( ( ! empty( $user ) && strlen( $user ) ) && ( $is_assistant || $is_admin ) ? $user : $login ); dbi_execute( 'DELETE FROM webcal_entry_categories WHERE cal_id = ? - AND ( cat_owner = ? OR cat_owner = "" )', [$id, $cat_owner] ); + AND ( cat_owner = ? OR cat_owner = ? )', [$id, $cat_owner, ''] ); if( ! empty( $cat_id ) ) { $categories = explode( ',', $cat_id ); diff --git a/includes/dbi4php.php b/includes/dbi4php.php index 354a83c93..553d9b9cf 100644 --- a/includes/dbi4php.php +++ b/includes/dbi4php.php @@ -355,7 +355,7 @@ function dbi_query( $sql, $fatalOnError = true, $showError = true ) { return OCIExecute( $GLOBALS['oracle_statement'], OCI_COMMIT_ON_SUCCESS ); } elseif( strcmp( $GLOBALS['db_type'], 'postgresql' ) == 0 ) { $found_db_type = true; - $res = pg_exec( $GLOBALS['postgresql_connection'], $sql ); + $res = @pg_exec( $GLOBALS['postgresql_connection'], $sql ); } elseif( strcmp( $GLOBALS['db_type'], 'sqlite' ) == 0 ) { $found_db_type = true; $res = sqlite_query( $GLOBALS['sqlite_c'], $sql, SQLITE_NUM ); @@ -367,9 +367,12 @@ function dbi_query( $sql, $fatalOnError = true, $showError = true ) { if( $found_db_type ) { if( ! $res ) { //echo "Db error: " . dbi_error() . "
\n"; - dbi_fatal_error( translate( 'Error executing query.' ) - . ( $phpdbiVerbose ? ( dbi_error() . "\n\n
\n" . $sql ) : '' ), - $fatalOnError, $showError ); + $verboseDetails = empty($phpdbiVerbose) ? '' : ('

' . dbi_error() . "\n\n
\n" . $sql); + dbi_fatal_error( + translate('Error executing query.') . $verboseDetails, + $fatalOnError, + $showError + ); } return $res; } else @@ -594,7 +597,8 @@ function dbi_free_result($res) } return true; // Assuming a successful operation as it's not directly supported. case 'postgresql': - return pg_freeresult($res); + pg_query_params($GLOBALS['postgresql_connection'], 'SELECT 1', []); // auto-free query + return true; case 'sqlite': // Not supported for SQLite, just return true. return true; @@ -638,7 +642,7 @@ function dbi_error() return htmlentities($e['message']); case 'postgresql': - return pg_errormessage($GLOBALS['postgresql_connection']); + return pg_last_error($GLOBALS['postgresql_connection']); case 'sqlite': if (empty($GLOBALS['db_sqlite_error_str'])) { @@ -707,7 +711,7 @@ function dbi_escape_string( $string ) { ? addslashes( $string ) : $db_connection_info['connection']->real_escape_string( $string ) ); case 'postgresql': - return pg_escape_string( $string ); + return pg_escape_string( $GLOBALS['postgresql_connection'], $string ); case 'sqlite': return sqlite_escape_string( $string ); case 'sqlite3': @@ -740,10 +744,7 @@ function dbi_escape_string( $string ) { * to the {@link dbi_fetch_row()} function to obtain the * results), or true/false on insert or delete queries. */ -function dbi_execute ( $sql, $params = [], $fatalOnError = true, - $showError = true ) { - - //echo "SQL: $sql
\n"; +function dbi_execute($sql, $params = [], $fatalOnError = true, $showError = true) { if( count( $params ) == 0 ) return dbi_query( $sql, $fatalOnError, $showError ); diff --git a/includes/functions.php b/includes/functions.php index aeb685b4f..4141d9631 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -804,7 +804,7 @@ function date_selection($prefix, $date, $trigger = false, $num_years = 20) * @return int Timestamp representing, in UTC or LOCAL time. */ function date_to_epoch( $d, $gmt = true ) { - if ( $d == 0 ) + if ( $d == 0 || $d === '' ) return 0; $dH = $di = $ds = 0; @@ -2580,7 +2580,13 @@ function get_groups($user, $includeUserlist=false) $sql = 'SELECT cal_login FROM webcal_group_user WHERE cal_group_id = ? ORDER BY cal_login'; $res = dbi_execute($sql, [$groups[$i]['cal_group_id']]); while ($row = dbi_fetch_row($res)) { - $users[] = $users_by_name[$row[0]]; + if (isset($users_by_name[$row[0]])){ + // It is possible some users assigned to this group may not exist, + // so we skip those that don't. For example, if users are fetched + // from an external source via user-app-*.php, and one of those + // users is deleted externally. + $users[] = $users_by_name[$row[0]]; + } } $groups[$i]['cal_users'] = $users; } diff --git a/install/index.php b/install/index.php index 03c1cb1ea..685c71392 100644 --- a/install/index.php +++ b/install/index.php @@ -63,17 +63,44 @@ function tryDbConnect() { - global $settings, $db_database; + global $settings, $db_database, $db_connection, $debugInstaller; if (!isset($settings['db_type']) || !isset($_SESSION['db_host']) || !isset($_SESSION['db_login']) || !isset($_SESSION['db_database'])) { return false; } try { - // Don't require database to exist in mysqli + // Don't require database to exist in mysqli and postgres if ($_SESSION['db_type'] == 'mysqli') { $mysqli = new mysqli($_SESSION['db_host'], $_SESSION['db_login'], $_SESSION['db_password']); if ($mysqli->connect_error) { return false; } + $db_connection = $mysqli; + return true; + } else if ( $_SESSION['db_type'] == 'postgresql') { + try { + $connString = "host=" . $_SESSION['db_host'] . " dbname=" . $_SESSION['db_database'] . " user=" . $_SESSION['db_login'] + . " password=" . $_SESSION['db_password']; + $c = @pg_connect($connString); + if ($c) { + $db_connection = $c; + if ($debugInstaller) + echo "Successful Postgres connection to " . $_SESSION['db_database'] . "
"; + return true; + } else { + if ($debugInstaller) + echo "First Postgres connection to " . $_SESSION['db_database'] . " FAILED
"; + } + } catch (Exception $e) { + // We may have failed because the db has not been created yet. So try again with the 'postgres' database. + if(!$debugInstaller) { + echo "First db connect attempt failed. Trying postgres db instead.
"; + } + } + $connString = "host=" . $_SESSION['db_host'] . " dbname=postgres user=" . $_SESSION['db_login'] . " password=" . $_SESSION['db_password']; + $c = @pg_connect($connString); + if (!$c) { + return false; + } return true; } else { $c = @dbi_connect( @@ -87,6 +114,9 @@ function tryDbConnect() } catch (Exception $e) { return false; } + if ($c) { + $db_connection = $c; + } return !empty($c); } @@ -261,17 +291,23 @@ function_exists('gd_info'), phpinfo (); exit; } -$emptyDatabase = $canConnectDb ? isEmptyDatabase() : true; +$databaseExists = false; +$emptyDatabase = false; +try { + // Try checking if there is a webcal_config table. If there is, then the db exists. + $emptyDatabase = isEmptyDatabase(); + } catch (Exception $e) { + // If we get an exception, then the db does not exist. + } $unsavedDbSettings = !empty($_SESSION['unsavedDbSettings']); // Keep track if Db settings were modified by not yet saved $reportedDbVersion = 'Unknown'; $adminUserCount = 0; -$databaseExists = false; $databaseCurrent = false; $settingsSaved = true; // True if a valid settings.php found unless user changes settings $detectedDbVersion = 'Unknown'; if ($canConnectDb && !empty($db_connection)) { $reportedDbVersion = getDbVersion(); - $detectedDbVersion = getDatabaseVersionFromSchema(); + $detectedDbVersion = getDatabaseVersionFromSchema(!$debugInstaller); if ($debugInstaller) { //echo "Db Version: $dbV
"; } diff --git a/install/install_ajax.php b/install/install_ajax.php index 24ca2eadc..51ace2f87 100644 --- a/install/install_ajax.php +++ b/install/install_ajax.php @@ -31,10 +31,15 @@ function testDbConnection($host, $login, $password, $database) $ret = true; $c->close(); } elseif ($_POST['dbType'] == 'postgresql') { - $c = pg_connect("host=$host dbname=$database user=$login password=$password"); + $c = @pg_connect("host=$host dbname=$database user=$login password=$password"); $ret = ($c !== false); - $error_msg = pg_last_error($c); - pg_close($c); + if (!$ret) { + $c = @pg_connect("host=$host dbname=postgres user=$login password=$password"); + $ret = ($c !== false); + } + if ($c) { + pg_close($c); + } } elseif ($_POST['dbType'] == 'ibase') { $c = ibase_connect($database, $login, $password); $ret = ($c !== false); diff --git a/install/install_createdb.php b/install/install_createdb.php index d42c9a77b..24b7e1dff 100644 --- a/install/install_createdb.php +++ b/install/install_createdb.php @@ -16,9 +16,9 @@

+if ($databaseExists) { + printNextPageButton($action); +} else { + printSubmitButton($action, null, translate('Create Database')); +} +?> \ No newline at end of file diff --git a/install/install_createdb_handler.php b/install/install_createdb_handler.php index 9adfe11eb..4490f1ac0 100644 --- a/install/install_createdb_handler.php +++ b/install/install_createdb_handler.php @@ -1,9 +1,12 @@ query($sql) === TRUE) { $conn->close(); + $existsMessage = str_replace("XXX", $databaseName, $existsMessage); + $_SESSION['alert'] = $existsMessage; return true; } else { throw new Exception("Error creating database: " . $conn->error); @@ -31,6 +36,7 @@ function createSqliteDatabase(string $filename): bool $db->exec("DROP TABLE dummy"); $db->close(); return true; + // TODO: Implement this... } catch (Exception $e) { throw new Exception("Error creating SQLite3 database: " . $e->getMessage()); } @@ -38,17 +44,34 @@ function createSqliteDatabase(string $filename): bool function createPostgresqlDatabase($hostname, $login, $password, $databaseName): bool { - $connString = "host={$hostname} user={$login} password={$password}"; + global $existsMessage, $createdMessage; + // Use specific query for existing database check (dbname=postgres) + $connString = "host={$hostname} dbname=postgres user={$login} password={$password}"; $db = pg_connect($connString); if (!$db) { - throw new Exception("Connection failed: " . pg_last_error()); + throw new Exception("Connection failed"); + } + $existsQuery = "SELECT 1 FROM information_schema.schemata WHERE schema_name = $1"; + $result = pg_query_params($db, $existsQuery, [$databaseName]); + if ($result) { + $row = pg_fetch_row($result); + if ($row && $row[0] === '1') { + // Database exists + pg_close($db); + $existsMessage = str_replace("XXX", $databaseName, $existsMessage); + $_SESSION['alert'] = $existsMessage; + return false; + } else { + // Database doesn't exist + } } - $result = pg_query($db, "CREATE DATABASE {$databaseName}"); if (!$result) { throw new Exception("Error creating database: " . pg_last_error($db)); } pg_close($db); + $createdMessage = str_replace("XXX", $databaseName, $createdMessage); + $_SESSION['alert'] = $createdMessage; return true; } diff --git a/install/install_functions.php b/install/install_functions.php index 626deb07c..a2e2c5abe 100644 --- a/install/install_functions.php +++ b/install/install_functions.php @@ -17,6 +17,9 @@ function isEmptyDatabase() { global $db_connection, $debugInstaller; if (empty($db_connection)) { + if ($debugInstaller) { + echo "No connection => empty db
"; + } return true; } try { @@ -499,7 +502,7 @@ function getDatabaseVersionFromSchema($silent = true) for ($i = 0; $i < count($database_upgrade_matrix); $i++) { $sql = $database_upgrade_matrix[$i][0]; if (!$silent) { - echo "SQL: $sql
\n"; + echo "SQL: $sql
Success: " . ($success ? "true":"false") . "\n
"; } if (empty($sql)) { @@ -507,6 +510,9 @@ function getDatabaseVersionFromSchema($silent = true) // We reached the end of database_upgrade_matrix[] with no errors, which // means the database is structurally up-to-date. $dbVersion = $PROGRAM_VERSION; + if (!$silent) { + echo "Complete success: version $dbVersion
\n"; + } } } else { try { diff --git a/install/sql/tables-mysql.sql b/install/sql/tables-mysql.sql index ee16eb722..c0bb7ebd1 100644 --- a/install/sql/tables-mysql.sql +++ b/install/sql/tables-mysql.sql @@ -280,7 +280,8 @@ CREATE TABLE webcal_site_extras ( /* how many minutes before event should a reminder be sent */ cal_remind INT DEFAULT 0, /* used to store text data */ - cal_data TEXT + cal_data TEXT, + PRIMARY KEY (cal_id, cal_name) ); /** diff --git a/install/sql/tables-postgres.sql b/install/sql/tables-postgres.sql index cf2ca4d1a..6cf5682a9 100644 --- a/install/sql/tables-postgres.sql +++ b/install/sql/tables-postgres.sql @@ -94,7 +94,8 @@ CREATE TABLE webcal_site_extras ( cal_type INT NOT NULL, cal_date INT DEFAULT '0', cal_remind INT DEFAULT '0', - cal_data TEXT + cal_data TEXT, + PRIMARY KEY (cal_id, cal_name) ); CREATE TABLE webcal_reminders ( cal_id INT DEFAULT '0' NOT NULL, @@ -158,7 +159,7 @@ CREATE TABLE webcal_categories ( cat_status CHAR DEFAULT 'A', cat_icon_mime VARCHAR(32) DEFAULT NULL, cat_icon_blob BYTEA DEFAULT NULL, - PRIMARY KEY ( cat_id, cat_order, cat_owner ) + PRIMARY KEY ( cat_id, cat_owner ) ); CREATE TABLE webcal_asst ( cal_boss VARCHAR(25) NOT NULL, @@ -184,8 +185,6 @@ CREATE TABLE webcal_import ( cal_md5 VARCHAR(32) NULL DEFAULT NULL, PRIMARY KEY ( cal_import_id ) ); -CREATE INDEX webcal_import_data_type ON webcal_import_data(cal_import_type); -CREATE INDEX webcal_import_data_ext_id ON webcal_import_data(cal_external_id); CREATE TABLE webcal_import_data ( cal_import_id INT NOT NULL, cal_id INT NOT NULL, @@ -194,6 +193,8 @@ CREATE TABLE webcal_import_data ( cal_external_id VARCHAR(200) NULL, PRIMARY KEY ( cal_id, cal_login ) ); +CREATE INDEX webcal_import_data_type ON webcal_import_data(cal_import_type); +CREATE INDEX webcal_import_data_ext_id ON webcal_import_data(cal_external_id); CREATE TABLE webcal_report ( cal_login VARCHAR(25) NOT NULL, cal_report_id INT NOT NULL, diff --git a/install/sql/upgrade-sql.php b/install/sql/upgrade-sql.php index 057d53d53..6f52e8e2c 100644 --- a/install/sql/upgrade-sql.php +++ b/install/sql/upgrade-sql.php @@ -155,6 +155,14 @@ function getSqlUpdates($currentVersion, $dbType = 'default', $includeFunctions = cal_date INT NOT NULL, PRIMARY KEY (cal_id,cal_date) ); +SQL, + 'posgresql-sql' => <<<'SQL' +ALTER TABLE webcal_user ALTER COLUMN cal_passwd TYPE VARCHAR(32); +CREATE TABLE webcal_entry_repeats_not ( + cal_id INT NOT NULL, + cal_date INT NOT NULL, + PRIMARY KEY (cal_id,cal_date) +); SQL ], [ @@ -167,7 +175,7 @@ function getSqlUpdates($currentVersion, $dbType = 'default', $includeFunctions = cat_owner VARCHAR(25), PRIMARY KEY (cat_id) ); -SQL +SQL, ], [ 'version' => 'v0.9.41', @@ -263,6 +271,14 @@ function getSqlUpdates($currentVersion, $dbType = 'default', $includeFunctions = ], [ 'version' => 'v1.1.0a-CVS', + 'postresql-sql' => <<<'SQL' +CREATE TABLE webcal_access_function ( + cal_login VARCHAR(25) NOT NULL, + cal_permissions VARCHAR(64) NOT NULL, + PRIMARY KEY (cal_login) +); +ALTER TABLE webcal_nonuser_cals ALTER COLUMN cal_is_public SET TYPE CHAR(1) NOT NULL DEFAULT 'N'; +SQL, 'default-sql' => <<<'SQL' CREATE TABLE webcal_access_function ( cal_login VARCHAR(25) NOT NULL, @@ -274,6 +290,32 @@ function getSqlUpdates($currentVersion, $dbType = 'default', $includeFunctions = ], [ 'version' => 'v1.1.0b-CVS', + 'postgresql-sql' => <<<'SQL' +CREATE TABLE webcal_user_template ( + cal_login VARCHAR(25) NOT NULL, + cal_type CHAR(1) NOT NULL, + cal_template_text TEXT, + PRIMARY KEY (cal_login,cal_type) +); +ALTER TABLE webcal_entry_repeats ADD COLUMN cal_endtime INTEGER DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD COLUMN cal_bymonth VARCHAR(50) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD COLUMN cal_bymonthday VARCHAR(100) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD COLUMN cal_byday VARCHAR(100) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD COLUMN cal_bysetpos VARCHAR(50) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD COLUMN cal_byweekno VARCHAR(50) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD COLUMN cal_byyearday VARCHAR(50) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD COLUMN cal_wkst CHAR(2) DEFAULT 'MO'; +ALTER TABLE webcal_entry_repeats ADD COLUMN cal_count INTEGER DEFAULT NULL; +ALTER TABLE webcal_entry_repeats_not ADD COLUMN cal_exdate BOOLEAN DEFAULT TRUE; +ALTER TABLE webcal_entry ADD COLUMN cal_due_date INTEGER DEFAULT NULL; +ALTER TABLE webcal_entry ADD COLUMN cal_due_time INTEGER DEFAULT NULL; +ALTER TABLE webcal_entry ADD COLUMN cal_location VARCHAR(100) DEFAULT NULL; +ALTER TABLE webcal_entry ADD COLUMN cal_url VARCHAR(100) DEFAULT NULL; +ALTER TABLE webcal_entry ADD COLUMN cal_completed BOOLEAN DEFAULT NULL; +ALTER TABLE webcal_entry_user ADD COLUMN cal_percent SMALLINT NOT NULL DEFAULT 0; +ALTER TABLE webcal_site_extras DROP CONSTRAINT webcal_site_extras_pkey; +ALTER TABLE webcal_site_extras ADD CONSTRAINT webcal_site_extras_pkey PRIMARY KEY (cal_id, cal_name); +SQL, 'default-sql' => <<<'SQL' CREATE TABLE webcal_user_template ( cal_login VARCHAR(25) NOT NULL, @@ -298,17 +340,19 @@ function getSqlUpdates($currentVersion, $dbType = 'default', $includeFunctions = ALTER TABLE webcal_entry ADD cal_completed INT(11) DEFAULT NULL; ALTER TABLE webcal_entry_user ADD cal_percent INT(11) NOT NULL DEFAULT '0'; ALTER TABLE webcal_site_extras DROP PRIMARY KEY; -SQL +ALTER TABLE webcal_site_extras ADD PRIMARY KEY (cal_id, cal_name); +SQL, ], [ 'version' => 'v1.1.0c-CVS', 'upgrade-function' => 'do_v11b_updates', 'default-sql' => <<<'SQL' CREATE TABLE webcal_entry_categories ( - cal_id int(11) NOT NULL DEFAULT '0', - cat_id int(11) NOT NULL DEFAULT '0', - cat_order int(11) NOT NULL DEFAULT '0', - cat_owner VARCHAR(25) DEFAULT NULL + cal_id INT NOT NULL DEFAULT 0, + cat_id INT NOT NULL DEFAULT 0, + cat_order INT NOT NULL DEFAULT 0, + cat_owner VARCHAR(25) DEFAULT NULL, + PRIMARY KEY ( cal_id, cat_id, cat_order, cat_owner ) ); SQL ], @@ -385,12 +429,24 @@ function getSqlUpdates($currentVersion, $dbType = 'default', $includeFunctions = ], [ 'version' => 'v1.1.2', + 'postgresql-sql' => <<<'SQL' +ALTER TABLE webcal_nonuser_cals ADD COLUMN cal_url VARCHAR(255) DEFAULT NULL; +SQL, 'default-sql' => <<<'SQL' ALTER TABLE webcal_nonuser_cals ADD cal_url VARCHAR(255) DEFAULT NULL; SQL ], [ 'version' => 'v1.1.3', + 'postgresql-sql' => <<<'SQL' +ALTER TABLE webcal_categories ADD COLUMN cat_color VARCHAR(8) DEFAULT NULL; +ALTER TABLE webcal_user ADD COLUMN cal_enabled CHAR(1) DEFAULT 'Y'; +ALTER TABLE webcal_user ADD COLUMN cal_telephone VARCHAR(50) DEFAULT NULL; +ALTER TABLE webcal_user ADD COLUMN cal_address VARCHAR(75) DEFAULT NULL; +ALTER TABLE webcal_user ADD COLUMN cal_title VARCHAR(75) DEFAULT NULL; +ALTER TABLE webcal_user ADD COLUMN cal_birthday INTEGER DEFAULT NULL; +ALTER TABLE webcal_user ADD COLUMN cal_last_login INTEGER DEFAULT NULL; +SQL, 'default-sql' => <<<'SQL' ALTER TABLE webcal_categories ADD cat_color VARCHAR(8) DEFAULT NULL; ALTER TABLE webcal_user ADD cal_enabled CHAR(1) DEFAULT 'Y'; @@ -421,16 +477,27 @@ function getSqlUpdates($currentVersion, $dbType = 'default', $includeFunctions = ], [ 'version' => 'v1.9.1', + 'postgresql-sql' => <<<'SQL' + ALTER TABLE webcal_import ADD COLUMN cal_check_date INTEGER DEFAULT NULL; + ALTER TABLE webcal_import ADD COLUMN cal_md5 VARCHAR(32) DEFAULT NULL; + CREATE INDEX webcal_import_data_type ON webcal_import_data(cal_import_type); + CREATE INDEX webcal_import_data_ext_id ON webcal_import_data(cal_external_id); + ALTER TABLE webcal_user ALTER COLUMN cal_passwd SET TYPE VARCHAR(255); + SQL, 'default-sql' => <<<'SQL' -ALTER TABLE webcal_import ADD cal_check_date INT NULL; -ALTER TABLE webcal_import ADD cal_md5 VARCHAR(32) NULL DEFAULT NULL; -CREATE INDEX webcal_import_data_type ON webcal_import_data(cal_import_type); -CREATE INDEX webcal_import_data_ext_id ON webcal_import_data(cal_external_id); -ALTER TABLE webcal_user MODIFY cal_passwd VARCHAR(255); + ALTER TABLE webcal_import ADD cal_check_date INT NULL; + ALTER TABLE webcal_import ADD cal_md5 VARCHAR(32) NULL DEFAULT NULL; + CREATE INDEX webcal_import_data_type ON webcal_import_data(cal_import_type); + CREATE INDEX webcal_import_data_ext_id ON webcal_import_data(cal_external_id); + ALTER TABLE webcal_user MODIFY cal_passwd VARCHAR(255); SQL ], [ 'version' => 'v1.9.6', + 'postgresql-sql' => <<<'SQL' +UPDATE webcal_entry_categories SET cat_owner = '' WHERE cat_owner IS NULL; +ALTER TABLE webcal_entry_categories ADD CONSTRAINT pkey_webcal_entry_categories PRIMARY KEY (cal_id, cat_id, cat_order, cat_owner); +SQL, 'default-sql' => <<<'SQL' UPDATE webcal_entry_categories SET cat_owner = '' WHERE cat_owner IS NULL; ALTER TABLE webcal_entry_categories ADD PRIMARY KEY (cal_id, cat_id, cat_order, cat_owner); @@ -445,15 +512,19 @@ function getSqlUpdates($currentVersion, $dbType = 'default', $includeFunctions = ALTER TABLE webcal_categories ADD cat_icon_blob LONGBLOB DEFAULT NULL; ALTER TABLE webcal_categories MODIFY cat_owner VARCHAR(25) DEFAULT '' NOT NULL; SQL, - 'postgres-sql' => <<<'SQL' -ALTER TABLE webcal_categories ADD COLUMN cat_status CHAR DEFAULT 'A'; + 'postgresql-sql' => <<<'SQL' +ALTER TABLE webcal_categories ADD COLUMN cat_status CHAR(1) DEFAULT 'A'; ALTER TABLE webcal_categories ADD COLUMN cat_icon_mime VARCHAR(32) DEFAULT NULL; ALTER TABLE webcal_categories ADD COLUMN cat_icon_blob BYTEA DEFAULT NULL; -ALTER TABLE webcal_categories MODIFY cat_owner VARCHAR(25) DEFAULT '' NOT NULL; +ALTER TABLE webcal_categories ALTER COLUMN cat_owner TYPE VARCHAR(25); SQL ], [ 'version' => 'v1.9.12', + 'postgres-sql' => <<<'SQL' +ALTER TABLE webcal_nonuser_cals ALTER COLUMN cal_url TYPE VARCHAR(255); +ALTER TABLE webcal_entry ALTER COLUMN cal_url TYPE VARCHAR(255); +SQL, 'default-sql' => <<<'SQL' ALTER TABLE webcal_nonuser_cals MODIFY COLUMN cal_url VARCHAR(255); ALTER TABLE webcal_entry MODIFY COLUMN cal_url VARCHAR(255); diff --git a/install/sql/upgrade_matrix.php b/install/sql/upgrade_matrix.php index 221c9869e..0f9377723 100644 --- a/install/sql/upgrade_matrix.php +++ b/install/sql/upgrade_matrix.php @@ -12,57 +12,57 @@ // WebCalendar version right in the database. This is kludge to deal with installations from // before then. $database_upgrade_matrix = [ - ['INSERT INTO webcal_view ( cal_name, cal_view_id, cal_is_global, cal_owner ) VALUES ( "delete-me", -999, "Z", "nobody" )', - 'DELETE FROM webcal_view WHERE cal_view_id = -999', - 'v0.9.43', 'upgrade_v1.0RC3'], - ['INSERT INTO webcal_access_function ( cal_login, cal_permissions ) VALUES ( "zzz","zzz" )', - 'DELETE FROM webcal_access_function WHERE cal_login = "zzz"', - 'v1.0RC3', 'upgrade_v1.1.0-CVS'], - ['INSERT INTO webcal_user_template ( cal_login, cal_type ) VALUES ( "zzz", "Z" )', - 'DELETE FROM webcal_user_template WHERE cal_login = "zzz"', - 'v1.1.0-CVS', 'upgrade_v1.1.0a-CVS'], - ['INSERT INTO webcal_entry_categories ( cal_id, cat_owner ) VALUES ( -999, "nobody" )', - 'DELETE FROM webcal_entry_categories WHERE cal_id = -999', - 'v1.1.0a-CVS', 'upgrade_v1.1.0b-CVS'], - ['INSERT INTO webcal_blob ( cal_blob_id, cal_type, cal_mod_date, cal_mod_time ) VALUES ( -999, "Z", 20200101, 0 )', - 'DELETE FROM webcal_blob WHERE cal_blob_id = -999', - 'v1.1.0b-CVS', 'upgrade_v1.1.0c-CVS'], - ['INSERT INTO webcal_access_user ( cal_login, cal_other_user ) VALUES ( "zzz", "zzz" )', - 'DELETE FROM webcal_access_user WHERE cal_login = "zzz"', - 'v1.1.0c-CVS', 'upgrade_v1.1.0d-CVS'], - ['INSERT INTO webcal_reminders ( cal_id ) VALUES ( -999 )', - 'DELETE FROM webcal_reminders WHERE cal_id = -999', - 'v1.1.0d-CVS', 'upgrade_v1.1.0e-CVS'], - ['INSERT INTO webcal_nonuser_cals ( cal_login, cal_admin, cal_url ) VALUES ( "zzz", "zzz", "zzz" )', - 'DELETE FROM webcal_nonuser_cals WHERE cal_login = "zzz"', - 'v1.1.0e-CVS', 'upgrade_v1.1.1'], - ['INSERT INTO webcal_categories ( cat_id, cat_name, cat_color, cat_owner ) VALUES ( "999", "zzz", "#FFFFFF", "nobody" )', - 'DELETE FROM webcal_categories WHERE cat_id = 999', - 'v1.1.1', 'upgrade_v1.1.2'], + ["INSERT INTO webcal_view ( cal_name, cal_view_id, cal_is_global, cal_owner ) VALUES ( 'delete-me', -999, 'Z', 'nobody' )", + "DELETE FROM webcal_view WHERE cal_view_id = -999", + "v0.9.43", "upgrade_v1.0RC3"], + ["INSERT INTO webcal_access_function ( cal_login, cal_permissions ) VALUES ( 'zzz','zzz' )", + "DELETE FROM webcal_access_function WHERE cal_login = 'zzz'", + "v1.0RC3", "upgrade_v1.1.0-CVS"], + ["INSERT INTO webcal_user_template ( cal_login, cal_type ) VALUES ( 'zzz', 'Z' )", + "DELETE FROM webcal_user_template WHERE cal_login = 'zzz'", + "v1.1.0-CVS", "upgrade_v1.1.0a-CVS"], + ["INSERT INTO webcal_entry_categories ( cal_id, cat_owner ) VALUES ( -999, 'nobody' )", + "DELETE FROM webcal_entry_categories WHERE cal_id = -999", + "v1.1.0a-CVS", "upgrade_v1.1.0b-CVS"], + ["INSERT INTO webcal_blob ( cal_blob_id, cal_type, cal_mod_date, cal_mod_time ) VALUES ( -999, 'Z', 20200101, 0 )", + "DELETE FROM webcal_blob WHERE cal_blob_id = -999", + "v1.1.0b-CVS", "upgrade_v1.1.0c-CVS"], + ["INSERT INTO webcal_access_user ( cal_login, cal_other_user ) VALUES ( 'zzz', 'zzz' )", + "DELETE FROM webcal_access_user WHERE cal_login = 'zzz'", + "v1.1.0c-CVS", "upgrade_v1.1.0d-CVS"], + ["INSERT INTO webcal_reminders ( cal_id ) VALUES ( -999 )", + "DELETE FROM webcal_reminders WHERE cal_id = -999", + "v1.1.0d-CVS", "upgrade_v1.1.0e-CVS"], + ["INSERT INTO webcal_nonuser_cals ( cal_login, cal_admin, cal_url ) VALUES ( 'zzz', 'zzz', 'zzz' )", + "DELETE FROM webcal_nonuser_cals WHERE cal_login = 'zzz'", + "v1.1.0e-CVS", "upgrade_v1.1.1"], + ["INSERT INTO webcal_categories ( cat_id, cat_name, cat_color, cat_owner ) VALUES ( '999', 'zzz', '#FFFFFF', 'nobody' )", + "DELETE FROM webcal_categories WHERE cat_id = 999", + "v1.1.1", "upgrade_v1.1.2"], // Upgrade from 1.1.2 -> 1.3.0 - ['INSERT INTO webcal_timezones ( tzid ) VALUES ( "zzz" )', - 'DELETE FROM webcal_timezones WHERE tzid = "zzz"', - 'v1.1.2', 'upgrade_v1.3.0'], + ["INSERT INTO webcal_timezones ( tzid ) VALUES ( 'zzz' )", + "DELETE FROM webcal_timezones WHERE tzid = 'zzz'", + "v1.1.2", "upgrade_v1.3.0"], // Upgrade from 1.3.0 -> 1.9.0 - ['INSERT INTO webcal_import (cal_import_id, cal_md5, cal_date, cal_type) VALUES (999999, "XXX", 1, "X")', - 'DELETE FROM webcal_import WHERE cal_import_id = 999999', - 'v1.3.0', 'upgrade_v1.9.0'], + ["INSERT INTO webcal_import (cal_import_id, cal_md5, cal_date, cal_type) VALUES (999999, 'XXX', 1, 'X')", + "DELETE FROM webcal_import WHERE cal_import_id = 999999", + "v1.3.0", "upgrade_v1.9.0"], // Upgrade from 1.9.0 -> 1.9.6 // Check to see if we can set cat_owner to NULL in webcal_entry_categories // Should get MySQL error: Column 'cat_owner' cannot be null - ['INSERT INTO webcal_entry_categories (cal_id, cat_id, cat_order, cat_owner) VALUES (999999, 1, -1, "")', - 'DELETE FROM webcal_entry_categories WHERE cal_id = 999999 AND cat_order = -1', - 'v1.9.0', 'upgrade_v1.9.6'], + ["INSERT INTO webcal_entry_categories (cal_id, cat_id, cat_order, cat_owner) VALUES (999999, 1, -1, 'nobody')", + "DELETE FROM webcal_entry_categories WHERE cal_id = 999999 AND cat_order = -1", + "v1.9.0", "upgrade_v1.9.6"], // Upgrade from 1.9.10 -> 1.9.11 - ['INSERT INTO webcal_categories (cat_id, cat_name, cat_owner, cat_icon_mime) VALUES (999999, "nocat", "nobody", "image/gif")', - 'DELETE FROM webcal_categories WHERE cat_id = 999999 AND cat_owner = "nobody"', - 'v1.9.10', 'upgrade_v1.9.11'], + ["INSERT INTO webcal_categories (cat_id, cat_name, cat_owner, cat_icon_mime) VALUES (999999, 'nocat', 'nobody', 'image/gif')", + "DELETE FROM webcal_categories WHERE cat_id = 999999 AND cat_owner = 'nobody'", + "v1.9.10", "upgrade_v1.9.11"], // Upgrade from 1.9.11 -> 1.9.12 - ["insert into webcal_entry (cal_id, cal_name, cal_create_by, cal_date, cal_duration, cal_url) values (-999, 'Test', 'nobody', 20201231, 0, '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789')", - 'delete from webcal_entry where cal_id = -999', - 'v1.9.11', 'upgrade_v1.9.12'], + ["INSERT INTO webcal_entry (cal_id, cal_name, cal_create_by, cal_date, cal_duration, cal_url) VALUES (-999, 'Test', 'nobody', 20201231, 0, '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789')", + "DELETE FROM webcal_entry WHERE cal_id = -999", + "v1.9.11", "upgrade_v1.9.12"], // don't change this array element - ['','', $PROGRAM_VERSION, ''] + ["","", $PROGRAM_VERSION, ""] ]; ?> diff --git a/remotecal_mgmt.php b/remotecal_mgmt.php index 74f23a4fc..c312d7e71 100644 --- a/remotecal_mgmt.php +++ b/remotecal_mgmt.php @@ -18,7 +18,7 @@ } $LOADING = '
Loading...
'; -$cannotLoadStr = translate('You PHP setting for allow_url_fopen will not allow a remote calendar to be loaded.'); +$cannotLoadStr = translate('Your PHP setting for allow_url_fopen will not allow a remote calendar to be loaded.'); $areYouSure = translate('Are you sure you want to delete this remote calendar?'); $deleteUserInfo = translate('This will remove all events for this remote calendar.') . ' ' . translate('This action cannot be undone.'); diff --git a/translations/English-US.txt b/translations/English-US.txt index 9e559656e..0a7ec916b 100644 --- a/translations/English-US.txt +++ b/translations/English-US.txt @@ -36,7 +36,7 @@ # Translate "May_" to the full month name and "May" to the, # usually three-letter, month abbreviation (like "Oct" for "October"). # -# Translation last updated on 12-08-2023 +# Translation last updated on 01-23-2024 charset: iso-8859-1 direction: ltr @@ -1928,6 +1928,12 @@ PHP Info: PHP Info # Database tables successfully created: Database tables successfully created +######################################## +# Page: install/install_createdb_handler.php +# +Database XXX already exists.: Database XXX already exists. +Created database XXX: Created database XXX + ######################################## # Page: install/install_ajax.php #