You are currently viewing Building a Gig Database with PHP for Underground Metal Shows

Building a Gig Database with PHP for Underground Metal Shows

When organizing a series of underground metal shows in Helsinki in 2012, you quickly realise that spreadsheets become unwieldy. Bands cancel, venues change, set times shift, and flyers need updating. A custom PHP system can track all this without relying on commercial ticketing platforms that often ignore the DIY ethos of the scene. This article walks through the practical decisions behind building a gig management tool using PHP—something that many Finnish thrash promoters have hacked together for their own use.

A PHP code editor showing database connection and query examples

Why PHP Still Fits the Underground

PHP powers a large share of independent music websites because it runs on cheap shared hosting and has a shallow learning curve. For a local scene with limited budget, a plain PHP script can handle gig listings, RSVPs, and even simple payment collection for pre-sale tickets. The language’s built-in date and time functions make scheduling straightforward—critical when you need to avoid clashes between two bands sharing a rehearsal space before a show.

In the Finnish thrash scene of the late 2000s, many bands maintained their own PHP-based sites using flat-file databases or MySQL. The flexibility allowed promoters to add fields like “gear requirements” or “backline notes” that commercial calendars never offered. A gig PHP system can be as minimal or as feature-rich as the organiser needs.

Core Data Model for a Gig Calendar

Before writing any code, define the entities that matter. A typical underground show involves:

  • Bands – name, genre, contact, social media links, rider notes.
  • Venues – name, address, capacity, stage dimensions, PA system details.
  • Events – date, doors time, start time, ticket price, promoter notes.
  • Lineup – which band plays at which slot, with set duration.

A simple relational schema in MySQL might look like this:

Table Key Columns
bands id, name, genre, contact_email, notes
venues id, name, address, capacity, pa_details
events id, venue_id, event_date, doors_time, start_time, ticket_price, promoter_notes
lineup id, event_id, band_id, slot_order, set_duration_minutes

This structure allows queries like “show all events where a specific band played in 2013” or “list upcoming shows at a venue with capacity under 200.” For a Finnish thrash archive, such queries help reconstruct tour itineraries from old flyers and forum posts.

Displaying the Calendar with PHP

Once the data is in place, the front-end needs to present it clearly. A common pattern is to fetch events for the current month and loop through them. Use PHP’s DateTime class to handle time zones—a Finnish winter gig might be listed in EET while a summer festival in Europe uses CEST.

A typical output loop:

$stmt = $pdo->query('SELECT e.id, e.event_date, e.doors_time, v.name AS venue_name, GROUP_CONCAT(b.name SEPARATOR ", ") AS bands FROM events e JOIN venues v ON e.venue_id = v.id JOIN lineup l ON l.event_id = e.id JOIN bands b ON l.band_id = b.id GROUP BY e.id ORDER BY e.event_date');
while ($row = $stmt->fetch()) {
    echo '<div class="gig">';
    echo '<h3>' . htmlspecialchars($row['event_date']) . ' @ ' . htmlspecialchars($row['venue_name']) . '</h3>';
    echo '<p>Bands: ' . htmlspecialchars($row['bands']) . '</p>';
    echo '</div>';
}

This snippet uses a JOIN to combine data from all four tables. The GROUP_CONCAT trick is handy for showing the lineup in a single line. For a larger archive, pagination and filtering by year or genre can be added.

A web page with a list of concert dates, venue names, and band lineups

Handling Recurring and Cancelled Events

Underground shows often get rescheduled or cancelled. A robust gig PHP system should include a status field (confirmed, cancelled, postponed) and a cancellation reason. For historical archives, you may want to keep cancelled events visible but marked. Use an ENUM column in the events table. When displaying, check the status and apply a CSS class like .cancelled.

Recurring events (e.g., a monthly thrash night) can be stored as a template with a recurrence rule. PHP’s DatePeriod class can generate future instances on the fly, but for a static archive it’s simpler to store each occurrence as a separate row. This avoids complexity and makes it easy to edit a single date.

Adding User Input: Submissions and Admin

For a collaborative archive, you might let promoters submit gigs. A PHP form with basic validation (date format, required fields) works well. Store submissions in a separate “pending” table and have an admin panel to approve them. Use sessions and a simple password hash for authentication—no need for OAuth when the user base is a handful of trusted archivists.

In the Finnish thrash scene, many old gig listings were posted on IRC or private forums. A PHP script that can import CSV files exported from those sources saves hours of manual entry. Build an import function that maps columns to your database fields and runs a batch INSERT.

Performance Considerations for a Small Archive

With a few hundred gigs, even a shared hosting server handles queries instantly. If you accumulate thousands of events over a decade, add indexes on event_date and venue_id. Use PHP’s memcached or file-based caching for the front page to avoid hitting the database on every request. For a static archive, you could even generate flat HTML files periodically using a cron job—PHP can write out a complete gig calendar as static pages, reducing server load to near zero.

Real-World Example: A Finnish Thrash Gig Archive

Suppose you want to document every show played by the band Axegressor between 2008 and 2015. With the schema above, you can run:

SELECT e.event_date, v.name, e.ticket_price FROM events e JOIN lineup l ON l.event_id = e.id JOIN bands b ON l.band_id = b.id JOIN venues v ON e.venue_id = v.id WHERE b.name = 'Axegressor' AND e.event_date BETWEEN '2008-01-01' AND '2015-12-31' ORDER BY e.event_date;

This returns a chronological list. You can then cross-reference with old flyers or setlist photos to verify accuracy. The same query can be wrapped in a PHP function that outputs a table for a band’s gigography page—a feature that collectors and historians appreciate.

Security and Maintenance

Even a small archive should use prepared statements (PDO or MySQLi) to prevent SQL injection. Escape output with htmlspecialchars(). Store passwords with password_hash(). Keep PHP and MySQL updated. For a long-running archive, schedule regular backups of the database—a simple mysqldump cron job will do.

One common mistake is displaying raw user-submitted text (e.g., promoter notes) without sanitization. Use strip_tags() or a whitelist of allowed HTML if you want to allow basic formatting. For historical accuracy, preserve the original wording but remove any embedded JavaScript.

Integrating with Other Tools

If you also maintain a discography database (like the one for Finnish thrash releases), you can link gigs to albums. Add an album_id foreign key in the events table to indicate which release was promoted on that tour. PHP can then show a “gigs supporting this album” section on each release page. This kind of cross-referencing turns a simple calendar into a rich historical resource.

For exporting data, PHP can generate iCal feeds for upcoming shows, or CSV files for researchers. The iCal format is especially useful—listeners can subscribe to the calendar in their phone and never miss a local thrash night.

Start Small, Expand Later

Begin with the four-table schema and a single PHP page that lists upcoming events. Add admin features only when the data grows. Use a local development environment (XAMPP or Docker) to test before deploying. The beauty of PHP is that you can iterate quickly—add a new field to the database, update the HTML, and reload. For a scene that values independence and self-reliance, a self-hosted gig system feels more authentic than any third-party platform.