Rescuing Legacy PHP: A Developer Disappeared Story
"Our developer stopped responding to emails three weeks ago. The application is broken and we don't know why. Can you help?"
This is how I got the call. A small business had been running an inventory management system built in 2012. The original developer had been maintaining it part-time for years, then suddenly ghosted them. No handoff, no documentation, no access to the server.
The system was down. They were managing inventory on spreadsheets. They were losing money.
The Initial Assessment
First, I needed access. The client had:
- Login credentials for the hosting control panel
- Access to the application (when it was working)
- The original developer's email (bouncing)
- Zero knowledge of how anything worked
What they didn't have:
- SSH access to the server
- Database credentials
- Any documentation whatsoever
- Source code repository
- Backup strategy
Great start.
Step 1: Get Server Access
I logged into their hosting control panel (cPanel). Found the application files via the file manager. Downloaded everything as a backup.
Then I enabled SSH access through cPanel and generated a new key. Now I could actually look at what was running.
Step 2: Read the Logs
Everyone says "read the logs" but nobody actually does it. I did.
tail -f /var/log/apache2/error.log Immediately saw the issue:
[PHP Fatal Error] Undefined index: user_id in /var/www/html/includes/auth.php on line 47 The authentication system was crashing because it expected a session variable that wasn't there. Classic PHP session issue.
Step 3: Understand the Codebase
I opened the codebase. It was... rough:
- 87 PHP files in a flat directory structure
- No framework, just raw PHP with
include()everywhere - Database queries directly in HTML templates
- Passwords stored in plain text (in the code)
- Zero comments except "// TODO: fix this later" from 2014
But it had been working for 11 years, so clearly the original developer knew what they were doing.
The Actual Problem
The hosting provider had upgraded PHP from 7.2 to 7.4 without telling anyone.
PHP 7.4 changed how sessions work. The old code assumed sessions were initialized automatically. They weren't anymore.
The fix:
// At the top of auth.php
if (session_status() === PHP_SESSION_NONE) {
session_start();
} Five lines of code. Site was back online in 20 minutes.
Step 4: Prevent This From Happening Again
Getting it working wasn't enough. I needed to make sure it stayed working.
Set Up Version Control
First thing: get this code into Git.
cd /var/www/html
git init
git add .
git commit -m "Initial commit - legacy rescue mission" Pushed it to a private GitHub repo. Now there's a backup and change history.
Document Everything
I created a README:
- How to access the server
- Database credentials (encrypted)
- How to restart services
- Common issues and fixes
- Backup procedures
Took 30 minutes. Could save hours later.
Set Up Automated Backups
The previous developer had been manually backing up the database "when he remembered." Last backup: 4 months old.
I wrote a simple backup script:
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
mysqldump -u username -ppassword dbname > backup_$DATE.sql
gzip backup_$DATE.sql
# Upload to S3
aws s3 cp backup_$DATE.sql.gz s3://client-backups/
# Keep only last 30 days locally
find . -name "backup_*.sql.gz" -mtime +30 -delete Added it to cron to run daily at 2am.
Set Up Monitoring
I set up UptimeRobot to ping the application every 5 minutes. If it goes down, the client and I both get SMS alerts.
Cost: $0 (free tier handles this fine)
Step 5: Document the Quirks
While poking around, I found some... interesting things:
- The database had a table called "stuff" with columns "thing1" through "thing9"
- There was a scheduled task that ran at 3:17am for no apparent reason
- Session timeout was set to 10 minutes, which users hated
- Passwords were validated client-side only (yikes)
I documented all of this with notes like "Don't touch - works somehow" for things that seemed weird but functional.
The Client's Question
"Should we rebuild this from scratch?"
My honest answer: Not yet.
Here's why:
- It works now (after the fix)
- It's been running their business for 11 years
- A rewrite would take 3-6 months and cost $20k-40k
- They'd be without features during development
- The ROI isn't there right now
Instead, I recommended:
- Keep it running with proper maintenance
- Fix security issues (passwords, SQL injection risks)
- Add basic tests for critical functions
- Document everything
- Plan a gradual migration in 1-2 years when budget allows
Sometimes the best solution is the boring one: just keep the old system running.
Security Quick Wins
I did make some immediate security fixes:
1. Hash the Passwords
Plain text passwords had to go. I added proper hashing:
// Old code
if ($user_pass === $stored_pass) {
// login
}
// New code
if (password_verify($user_pass, $stored_hash)) {
// login
} Migrated existing users gradually with a "reset password" flag.
2. Fix SQL Injection
The original code had gems like:
$query = "SELECT * FROM users WHERE id = " . $_GET['id']; Changed to prepared statements:
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]); Boring but necessary.
3. Add HTTPS
The site was running on HTTP. Set up Let's Encrypt SSL certificate (free) and forced HTTPS redirect.
Lessons Learned
Always read the logs first.
The error log told me exactly what was wrong in 30 seconds. I wasted an hour looking at code before I thought to check the logs.
Legacy code isn't automatically bad.
This codebase was messy, but it had been reliably running a business for over a decade. That's worth something.
Don't rewrite without a good reason.
The impulse is always to throw away old code and start fresh. But rewrites are expensive, time-consuming, and often introduce new bugs. Sometimes the right move is to just maintain what exists.
Documentation saves lives.
If the original developer had left even basic documentation, this would've been a 10-minute fix instead of a multi-hour investigation.
The Aftermath
The application has been running smoothly for 8 months now. The client calls me once a month for small tweaks and updates. They're happy, users are happy, and nobody wants to talk about a rewrite anymore.
Is it elegant code? No. Would I write it this way today? Absolutely not. Does it work? Yes. That's all that matters.
Sometimes being suboptimal is optimal enough.