Table of Contents
About WebCalendar
WebCalendar is a PHP-based calendar application that can be configured as a single-user calendar, a multi-user calendar for groups of users, or as an event calendar viewable by visitors. MySQL/MariaDB, SQLite3, PostgreSQL, Oracle, DB2, Interbase, MS SQL Server, or ODBC is required. The version 1.9.X releases are still a little rough around the edges since these include an overhaul of the UI to use Bootstrap and jQuery and a complete rewrite of the web-based installer.
WebCalendar can be setup in a variety of ways, such as…
- A schedule management system for a single person
- A schedule management system for a group of people, allowing one or more assistants to manage the calendar of another user
- An events schedule that anyone can view, allowing visitors to submit new events
- A calendar server that can be viewed with iCalendar-compliant calendar applications like Mozilla Sunbird, Apple iCal or GNOME Evolution or RSS-enabled applications like Firefox, Thunderbird, RSSOwl, FeedDemon, or BlogExpress.
Overview of Features
- Multi-user support
- 30 supported languages: Basque, Bulgarian, Chinese-Big5, Chinese-GB2312, Czech, Danish, Dutch, English-US, Estonian, Finnish, French, Galician, German, Greek, Holo-Big5, Hungarian, Icelandic, Italian, Japanese, Korean, Norwegian, Polish, Portuguese_BR, Portuguese, Romanian, Russian, Spanish, Swedish, Turkish, Welsh (see current list of translations here)
- Web-based installer
- Auto-detect user’s language preference from browser settings
- View calendars by day, week, month or year
- View another user’s calendar
- View one or more users’ calendar via layers on top of your own calendar
- Add/Edit/Delete users
- Add/Edit/Delete events
- Repeating events including support for overriding or deleting (exceptions)
- Configurable custom event fields
- User-configurable preferences for colors, 12/24 time format, Sun/Mon week start
- Checks for scheduling conflicts
- Email reminders for upcoming events
- Email notifications for new/updated/deleted events
- Export events to iCalendar
- Import from iCalendar/ics format
- Optional general access (no login required) to allow calendar to be viewed by people without a login (useful for event calendars)
- Users can make their calendar available publicly to anyone with an iCalendar-compliant calendar program (such as Apple’s iCal, Mozilla Calendar or Sunbird)
- Publishing of free/busy schedules (part of the iCalendar standard)
- RSS support that puts a user’s calendar into RSS
- Subscribe to “remote” calendars (hosted elsewhere on the net) in either iCalendar or hCalendar formats (WebCalendar 1.1+)
- User authentication: Web-based, HTTP, LDAP or NIS
System Requirements
- PHP 8 or later
- PHP support and access to one of the following databases:
- SQLite
- MySQL/MariaDB
- Oracle
- Postgres
- IBM DB2
- Access to cron for Linux/Unix systems (to send out reminders)
Development Cost
The following metrics from Ohloh show how much it would have cost to commercially develop WebCalendar.
- Codebase Size: 138,588 lines
- Estimated Effort: 34 person-years
- Estimated Cost: $1,884,469
- (As of 11 August 2024)
Donations
If you’d like to help support the costs of developing, maintaining and supporting WebCalendar, please consider donating.
Developer Resources
- Github page for WebCalendar:
- Issues
- Pull requests
- Wiki
- Download the development code as a zip file
License
WebCalendar is available under the GNU General Public License, version 2.
For more information on this license:
Documentation
- System Administrator’s Guide
Introduction, installation instructions and FAQ - UPGRADING (WebCalendar 1.3.0)
Provides instruction on upgrading to version 1.3.7 from an older version - Database Design (WebCalendar 1.3.0)
Version 1.2.7 database schema
Most Recent Changes
Below are the most recent source code commits to github on the master branch.
- fix: bypass and clear stale query cache for WEBCAL_PROGRAM_VERSION (#…by craigk5n on April 17, 2026 at 11:46 am
fix: bypass and clear stale query cache for WEBCAL_PROGRAM_VERSION (#639) Aad’s latest report in #639 pinned the bug: webcal_config actually contained WEBCAL_PROGRAM_VERSION = v1.9.16 (he verified directly in the DB), yet config.php kept reporting “Database upgrade required (version v1.3.0 -> v1.9.16)” and redirecting back to the wizard on every request. Root cause is dbi4php’s on-disk query cache. includes/config.php:367 and includes/classes/WebCalendar.php:669 both read the version stamp via dbi_get_cached_rows(), which persists SELECT results to {db_cachedir}/*.dat and returns them for all future callers. The cache invalidation that dbi_query() runs on non-SELECT statements only fires when the write goes through dbi_execute(); the wizard’s updateVersionInDb() uses native mysqli/pg/sqlite3 directly, so the .dat file written while the DB was still at v1.3.0 stayed valid forever and pinned that value in the bootstrap version check. Three-part fix: 1. includes/config.php: drop the cache on the bootstrap version read. The cost is a single extra SELECT per request; correctness here is worth far more than one tiny cached row. 2. includes/classes/WebCalendar.php: same treatment for the duplicate version check. Also repoint its “mismatch” redirect at wizard/index.php — the hardcoded install/index.php target was dead code left over from #608 and would have 404’d if anything reached it. 3. WizardDatabase::executeUpgrade(): after a successful upgrade, wipe {dbCacheDir}/*.dat via direct filesystem ops so any OTHER stale cached queries (PUBLIC_ACCESS, user prefs, etc.) get refreshed on the next request. No dbi4php dependency needed for the cleanup. Tests cover the cache-clear step (stale .dat file gets removed after executeUpgrade) and the noop-when-no-cachedir guard.
- fix: make schema probe authoritative over stale version stamp (#639)by craigk5n on April 16, 2026 at 9:00 pm
fix: make schema probe authoritative over stale version stamp (#639) checkDatabase() ran the WEBCAL_PROGRAM_VERSION lookup first and only fell back to the schema probe when no config row existed. If an earlier upgrade crashed before updateVersionInDb() ran, or if the stamp was never written for any other reason, the stamp pointed at an old version while the schema actually reflected something newer — and we trusted the stamp, then re-ran every migration from the old stamp forward. That’s Aad’s post-install-stuck-at-v1.3.0 symptom in #639. Flip the priority: run both sources, reconcile via a new reconcileDbVersion() helper, and pick the higher of the two. A partial upgrade now self-corrects — the schema probe walks $database_upgrade_matrix and reports the actual state, so the wizard only runs the migrations that haven’t been applied yet. When the reconciled version matches programVersion but the stamp is stale, we still mark isUpgrade=true so executeUpgrade() runs its final updateVersionInDb() and fixes the stamp. Document idempotency expectations at the top of upgrade-functions.php: schema detection handles SQL-only partial upgrades because ignorable errors and CREATE TABLE IF NOT EXISTS make re-runs safe, but the PHP helpers here (especially do_v11b_updates’ “cal_end + 1 day” loop) are not idempotent and can corrupt data if they abort mid-flight. Tests cover the reconciliation rules: higher schema wins over stale config, higher config is not downgraded by a behind-schema probe, ‘Unknown’/null sources fall back cleanly.
- fix: cat_owner NULL cleanup, version-stamp error check, and SQL in er…by craigk5n on April 16, 2026 at 8:26 pm
fix: cat_owner NULL cleanup, version-stamp error check, and SQL in errors (#639) Three fixes from Aad’s multi-part report, plus tier-1 smoke tests for the upgrade helper functions restored in the previous commit. A. wizard/shared/upgrade-sql.php v1.9.11 was doing ALTER TABLE webcal_categories MODIFY cat_owner VARCHAR(25) DEFAULT ” NOT NULL without a preceding UPDATE to clear NULL rows, so MariaDB in strict mode aborted the upgrade with “Data truncated for column ‘cat_owner’ at row 1” for anyone upgrading from pre-v1.9.11. Add the same defensive UPDATE we already use for webcal_entry_categories at v1.9.6 to the default/postgresql/sqlite3 branches. B. WizardDatabase::updateVersionInDb was blindly returning true regardless of whether the INSERT … ON DUPLICATE KEY UPDATE / ON CONFLICT / INSERT OR REPLACE actually succeeded. If the write silently failed, the wizard reported a successful install but WEBCAL_PROGRAM_VERSION never landed in webcal_config and every subsequent request redirected back to the wizard. Check each driver’s return and propagate a descriptive error. C. executeCommand’s error message was bare $connection->error with no indication of which statement failed. Aad had to eyeball the preview SQL and guess. Add formatCommandError() that appends the failing SQL (truncated in the middle if very long) to the engine error. Smoke tests: – tests/UpgradeFunctionsSmokeTest runs each restored upgrade helper against an empty SQLite schema, confirming they load, call without crashing, and the v1.9.11 icon path handles missing/empty dirs. – tests/UpgradeSqlTest gets regression coverage for A (UPDATE before MODIFY), B (updateVersionInDb failure surfaces), and C (error includes truncated SQL).
- fix: restore upgrade helper functions dropped in wizard rewrite (#639)by craigk5n on April 16, 2026 at 8:18 pm
fix: restore upgrade helper functions dropped in wizard rewrite (#639) install/install_functions.php contained do_v11b_updates (v1.1.0c-CVS), do_v11e_updates (v1.1.0e-CVS), and do_v1_9_11_updates (v1.9.11) — all referenced from the upgrade matrix via ‘upgrade-function’. When the installer was rewritten as wizard/ in #608, the SQL-only pieces were ported but these three PHP migrations were dropped on the floor. WizardDatabase::executeCommand silently returned true when the named function didn’t exist, so any v1.3.0 -> v1.9.x upgrade path quietly skipped: – recurring-event cal_byday rewrites (yyyyyyy mask -> SU,MO,…) – exclusive end-date adjustment (+1 day) and priority remapping – reminder migration from webcal_site_extras (cal_type=7) to webcal_reminders, plus drop of obsolete webcal_reminder_log – category icon migration from wc-icons/ to webcal_categories.cat_icon_blob Restore all three verbatim (with the icon path fixed for the new wizard/shared/ location and die_miserable_death() replaced with a logged skip so a single unreadable icon doesn’t abort the upgrade) in wizard/shared/upgrade-functions.php. Lazy-load from executeCommand and surface a real error when a referenced function is missing rather than silently returning success. Add tests/UpgradeSqlTest test that scans the upgrade matrix and fails if any ‘upgrade-function’ name doesn’t resolve.
- docs: align wizard README with soft-removal posture (#639)by craigk5n on April 16, 2026 at 4:56 pm
docs: align wizard README with soft-removal posture (#639) wizard/steps/finish.php and security_audit.php were updated in #610 to stop recommending deletion of wizard/ and to surface the issue through the Security Audit instead, but wizard/README.md still carried the old “remove wizard/” guidance. Aad followed that advice in #639 and hit the runtime require fatal that was separately fixed in this branch. Replace the delete-the-wizard instructions with the current posture: run Security Audit, or restrict with chmod 000 / move outside web root if extra hardening is wanted. Note that outright deletion breaks upgrade detection at runtime.
Download Metrics
- Downloads via Github: 20135
- Downloads via SourceForge:
Related Links
- Standards
- Calendar client applications – You can use the applications to view events stored in WebCalendar if you enable its publishing settings.
- iCalendar/ics download sites – These sites contain calendars for holidays, sports teams schedules, music converts, etc. You can import these files into WebCalendar.
- iCalShare
- Apple iCal Library
- DateDex
- Project24: holiday and weather calendars