Shane Sturgeon
← All posts

Stay on Target: How I Stopped Planning and Started Building a 20-Year-Old PHP Site

The hardest part of resurrecting a legacy project isn't the code. It's resisting the urge to rearchitect everything before you've gotten a single page to load.

HDTV Magazine circa 2013

This post is part of the Ground-Level: HDTV Magazine Revival series. See all posts →

HDTV Magazine circa 2013 — the starting point of the revival

On New Year's Day 2026, I opened a GitHub repo and started resurrecting a website I helped co-found back in 2005. I didn't have a project plan. I had a zip file of 20-year-old PHP and a loose theory that running a real project would teach me more than any certification course. Plus I knew there was some good AI fodder in the 4,000+ articles we had amassed over the 10-year run of the site.

I have seen engineers (myself included) spend a week planning an architecture for a project that still doesn't have a working local environment. It feels productive but unless you're moving features to PROD, you're still planning. The thing that gets you moving is a page that loads in a browser.

I was constantly tempted to chase the architectural rabbits into holes and it takes some serious will power to stay the course - but that's the job. You need to resist the "well, while I'm in here…" urges and stay focused. That's how I teach my teams to organize their work, so that's what I needed to do as well.

Stay on target

Pick a thread and pull

The hardest part of a project like this isn't the technical work, it's figuring out where to start. The codebase was PHP 5.2, last touched around 2013, running on MySQL V-something.old with no dependency management, no error handling to speak of, and deprecation warnings everywhere.

I spent about fifteen minutes looking at it and decided not to plan. I just picked a thread and started pulling - let's just get the index page to load. Nothing else mattered until that was true.

Docker first, everything else second

First decision: local dev environment. I'm ashamed to admit this, but when I was developing this site 15-20 years ago, my dev environment consisted of a local file system, a text editor (TextWrangler) and an FTP server. That's right - I was editing files locally and just pushing them via FTP to the server - no git - no docker - no pipeline - no testing.

Well, this time I wanted to do it the "right" way. More specifically, I wanted to use the same processes, tools and utilities that my teams used on a daily basis. I know them conceptually, but my hands-on experience was extremely limited. So I started with the obvious (to me) choice: Docker. I set up a docker-compose.yml with three services: PHP + Apache, MariaDB, PHPMyAdmin -- nothing fancy, because the goal was to not be fighting my environment while I was already fighting the code.

For IDE: I went back and forth between VSCode, JetBrains and Cursor - ultimately deciding on JetBrains based on many reddit recommendations. This was also the most popular IDE among the teams I support, so it made sense for me to use it as well. If your IDE can talk to Docker and run your debugger, you have enough.

If you're interested, the original source code is now available in the HDTVMagazine-Legacy repo on GitHub. Fair warning: it's a mess.

The PHP and MariaDB version question

This is where some people get stuck. The codebase was written for PHP 5.2. Do you start there for compatibility, or do you jump to the latest version and fix whatever breaks?

I started at PHP 7.4, which was a deliberate midpoint - old enough that most legacy syntax still worked, new enough that I wasn't running something completely unsupported. My plan was to get things working and move up later, not solve all the version problems upfront.

Same logic for MariaDB. I started with MariaDB 5.7 in Docker because that was closest to what the original site ran on, knowing I'd move to RDS eventually, but that was a later-problem.

Start early, fail fast, pivot later.

Composer and dependency management

The original codebase had no dependency management. Libraries were literally copied into the repo, versions unknown. First thing I did was wire in Composer, which is the standard PHP dependency manager, and start moving those libraries to proper packages with versioned dependencies.

While I was at it, I added Whoops for error handling. Whoops is a PHP error page library that replaces the default blank white screen with a detailed stack trace. Having a drop-in debugging tool like that was HUGE. I only ran it locally though, not in prod. It can expose a little too much in prod via stack traces, etc. that you really want to try and avoid it. I did enable it for short bursts to troubleshoot issues that were only in prod (they ended up being database permissions mostly), but stick with local-only to start. APP_ENV=dev in my .env and then check for that when you're loading - simple.

Replacing deprecated database calls

PHP 5.2 used mysql_* functions directly for database access. Those functions were deprecated in PHP 5.5 and removed entirely in PHP 7. Since I was starting on PHP 7.4, they were just gone, which meant every database call in the app was broken.

I replaced them with PDO - a modern PHP database abstraction layer that supports parameterized queries, which also meant I was fixing a bunch of latent SQL injection vulnerabilities as a side effect. This was actually a big deal, and I didn't fully realize it until I ran SonarCloud months later. More on that in the security post.

This was not a quick find-and-replace. The original queries were string-concatenated and scattered everywhere, but if you are going to touch the database layer at all, do it once, do it right, and move on.

Getting the first page to load

With Docker up, Composer wired in, and the database calls migrated to PDO, I started the container and navigated to localhost.

A page loaded -- it looked terrible, CSS missing in places, images broken, PHP warnings still in the logs -- and it was also one of the more satisfying moments of this entire project.

The site was running again!

What I would do differently (short list)

Nothing major, honestly. The only thing I would change is I didn't commit the initial Docker setup early enough. I mutated it a few times before the first real commit, which meant I lost the history of some early decisions. Commit early. The history is part of the project.

Anyway, once the first page loaded, the next question was immediate: I needed to choose an AI coding tool. I tried several before I found one that actually fit the way I work. That's the next post.

Share:LinkedIn ↗

Get new posts in your inbox