Restoring a Classic: The All-New PHP Pick ‘Em for the 2026–2027 NFL Season

Regular readers know I have a soft spot for restoration projects. Usually that means a creased instruction manual, a worn 78rpm label, or a database that hasn’t been opened since 2007. This time, the restoration project was software: Kevin Roth’s original 2013 PHP Pick ‘Em, the free web application that let anyone self-host a weekly NFL football pool.

The original was a workhorse in its day, but its day was a long time ago. It was written for PHP 4/5 and MySQL 4, stored passwords with a custom triple-DES encryption scheme, and got its scores by scraping XML from NFL.com — a technique that stopped working years ago. Rather than let a good idea die, I rebuilt it from the ground up. The result is the all-new PHP Pick ‘Em, ready for the 2026–2027 season, and it’s free and open source on GitHub:

github.com/canon2k5/phppickem

What It Does

PHP Pick ‘Em runs a complete weekly NFL pick ’em pool on your own server. Players sign up, make their picks each week, and the app handles scoring, standings, tiebreakers, and automated email reminders. There’s a full admin dashboard for managing users, editing schedules, entering or auto-fetching scores, and resetting everything for a new season. If you’ve ever run an office pool on a spreadsheet and a prayer, this replaces all of it — and because it’s self-hosted, your league’s data stays on your server, with no subscription fees and no ads.

A Ground-Up Rewrite, Not a Patch Job

I want to be clear about what “rewrite” means here, because it would have been easy to slap a new coat of paint on the old code and call it modernized. Instead, nearly every subsystem was rebuilt.

Security came first. The old triple-DES password scheme is gone, replaced with PHP’s native bcrypt hashing. Every database query that touches user input now uses prepared statements — the raw SQL string concatenation scattered through the original files has been completely removed. Every state-changing form is protected by CSRF tokens, sessions are hardened against fixation attacks, credentials live outside the web root, and pick submissions run inside database transactions so a mid-save failure can’t leave a player with half a week’s picks recorded.

Scores and schedules are now API-driven. The original scraped NFL.com’s XML feed, which is exactly as fragile as it sounds. The new version pulls schedules and live scores from the BallDontLie NFL API with proper token authentication. A schedule builder script generates a ready-to-import SQL file for any season, and a web-based importer (with dry-run preview) handles the rest. When the 2027 season rolls around, updating is a one-command affair.

The stack is current. PHP 8.x with Composer, MariaDB/MySQL on InnoDB with full utf8mb4 Unicode support, Symfony Mailer in place of the ancient bundled PHPMailer classes, and a Bootstrap 5 frontend. The old pile of local JavaScript — jQuery, jQuery UI, Modernizr, assorted plugins — is gone entirely, replaced with vanilla JS and Bootstrap utilities.

It looks like something built this decade. There’s a full dark mode that respects your OS preference, a redesigned admin dashboard with live weekly stats, a rebuilt standings page, a team directory organized by conference and division, and clean typography throughout. Six-plus CSS files became one.

What’s New for Admins

Running the pool is where the rewrite really pays off. The admin dashboard shows at a glance how many players are active, who’s submitted picks, and whether this week’s scores are in — and it knows when it’s the off-season. A grouped table-reset utility handles the annual turnover: a “New Season Reset” clears picks and schedules while keeping your users, and it requires typing RESET to confirm, so nobody nukes the league by accident. Email templates (weekly reminders, results, final standings, and a new season-kickoff announcement) are editable right in the app with live preview variables. There are even CLI utilities for password resets when you’d rather work from the terminal.

Installation

The install is straightforward and fully documented in the README: copy the files, run composer install, create a database, drop your credentials into an environment file outside the web root, and walk through the four-step web installer. The installer even detects bundled season schedule files and offers to import them for you. You’ll need Apache or Nginx, PHP 8.1+, and MariaDB or MySQL 5.7+.

One important note for anyone who ran the original: this version is not database-compatible with the 2013–2015 releases. The schema, storage engine, character set, team abbreviations, and password storage have all changed. Start fresh with a clean install — it’s a fifteen-minute job, and your league will thank you.

Credit Where It’s Due

Kevin Roth wrote the original PHP Pick ‘Em in 2013 and deserves full credit for the concept and the foundation. This rewrite keeps his name in the license alongside mine, and the project remains MIT-licensed — free to use, modify, and share.

If you run a league with it, find a bug, or have a feature idea, the GitHub repository is the place to go. And if it saves your office pool from spreadsheet purgatory, there’s a donate button in the app that’s always appreciated.

Happy picking — and good luck in Week 1.