# 07 — Code health

## PHP version compatibility

The codebase was written for PHP 5.x. Several patterns **fatal under PHP 7.0+** and must be fixed before any upgrade:

### Removed in PHP 7.0 — will fatal
- **`mysql_*` function family** (`mysql_pconnect`, `mysql_query`, `mysql_fetch_object`, `mysql_real_escape_string`)
  - `httpdocs/inc/order.php`
  - `httpdocs/inc/sitemap.php`
  - `httpdocs/classes_new/minibots.class.php`
  - `affiliates/affiliate/` — **the entire iDevAffiliate v4.0 codebase** uses `mysql_*`, as do `affiliates/affiliate/admin/mysql.php` and most admin scripts. This is vendor code; upgrading requires replacing the product or forking it.
- **`get_magic_quotes_gpc()`** — removed 5.4, returns `false` on 7+ (tolerated but useless)
  - `httpdocs/auth/classes/sdba/sdba.php` (line ~64)

### Deprecated in PHP 8.1, fatal in 8.2+
- **Implicit nullable parameters** (`function f($x = null)`) — generate `Deprecated` warnings
- **Dynamic property creation** on non-stdClass objects — `Deprecated`
- **`strftime()`, `utf8_encode()`, `utf8_decode()`** — `Deprecated`

### Other likely PHP 8 hazards (spot-check recommended)
- `each()` usage in foreach patterns
- `create_function()` in event-handler style code
- Array-offset access on `null`/`false` — produces warnings under strict mode
- `parse_str(null, ...)` — `TypeError` in 8.1+

## Deprecated idioms

- **Singleton DB access** via `Sdba::table()` is fine, but some callers still open a raw `mysqli_connect()` in-line
- **Procedural session handling** with `session_start()` at the top of every entry point — duplicated, error-prone
- **No autoloader**: files `require_once` each other by relative path. Hardcoded path at `httpdocs/advertisers/index.php` line 65 (`/var/www/html/searchmercials/httpdocs/search`) means **the host path cannot change** without editing source

## Backup / "*_old" litter

Legacy versions retained side-by-side with live code. Non-exhaustive list:

| Live | Legacy copy |
|------|-------------|
| `httpdocs/search/dsX/Addons/backfill.inc` | `backfill.inc.bak` |
| `httpdocs/search/r.php` | `r.php.bak` |
| `httpsdocs/r.php` | `r.php_old` |
| `httpdocs/pages/advertisers.php` | `advertisers_old.php` |
| `httpdocs/pages/publishers.php` | `publishers_old.php` |
| `httpsdocs/index.php` | `index.php_old` |
| `httpsdocs/receive-payment.php` | `receive-payment.php-04032015` |
| `httpsdocs/search_old/`, `httpdocs/search/data_old/` | entire archived trees |
| `httpsdocs/validation_old/` | archived validation tree |
| `data/config.inc` | `data/config.inc.save`, `data/config_bu_9-23.inc` |
| `data/global.config` (implied) | `data/global.config.save`, `data/global.config.backup` |
| `data/config/arism.inc`, `avideo.inc`, `searchtube.config`, `searchtube_com.inc` | matching `*.save` siblings |
| `data/templates/default/` | `data/templates/default - Copy/`, `detail_old.txt`, `search_OLD.txt`, `default_alex.txt` |
| `affiliates/searchmercials_com/` | `affiliates/searchmercials_com_old/` |
| `affiliates/searchmercials_com/r.php` | `affiliates/searchmercials_com/r_not_used.php` |

**Impact**:
- Disk noise
- Risk of routing traffic to an old endpoint by mistake
- Dependency confusion — unclear which copy a given include reaches
- Some old copies may contain patched-out vulnerabilities that got reintroduced when re-deployed

**Action**: delete all `*_old`, `*_bak`, `*.bak`, and dated filenames. Git history preserves anything worth preserving.

## Hardcoded values

| Location | Value | Issue |
|----------|-------|-------|
| `httpdocs/advertisers/index.php` line 65 | `/var/www/html/searchmercials/httpdocs/search` | Host path hard-baked; breaks on any other host |
| `httpdocs/joe.php` line 12 | `10.0.0.49:3128` (proxy) | Internal network reference in source |
| `httpdocs/auth/classes/sdba/dbconnect.php` | DB passwords (plain text) | See [08-security-audit.md](08-security-audit.md) |
| `64.250.180.23` script | self-named after an IP | No abstraction over hosts |

## Debug / dev artifacts in production tree

Should be deleted or permission-restricted:

- `httpdocs/search/phpinfo.php` — exposes full PHP config
- `httpdocs/joe.php` — YP-API probe tool
- `httpdocs/submissions/test/` — URL scrapers, meta extractors
- `httpsdocs/settings.php` — unreviewed; check whether it's a config or a debug endpoint
- Any `.bak` / `_old` file served statically by Apache

## Dead code signals

- `httpdocs/includes/` appears empty — confirm and remove if so
- Duplicate `admin.php` in `httpdocs/` and `httpsdocs/`: determine which is canonical
- `httpsdocs/r.php_old`, `httpsdocs/index.php_old` — old route versions that may still be reachable if Apache indexes `.php_old` as PHP (it shouldn't by default, but **test** before assuming)

## Test coverage

**Zero**. No `tests/`, `phpunit.xml`, CI config, or assertion harness. Changes are validated manually. This is the single largest risk factor for any modernization effort.

## Observability

- No structured logging (no Monolog, no Sentry, no log aggregation hooks)
- No metrics / health endpoints
- No tracing

## Recommended remediation order

1. **Bottom-up PHP 7+ compatibility**: rewrite the three `mysql_*` files in `httpdocs/inc/` and `minibots.class.php`. Pin PHP-FPM to 7.4 first, then 8.1.
2. **Delete litter**: `*_old`, `*.bak`, dated duplicates. Git remembers.
3. **Autoload everything**: add a `composer.json` with PSR-4 autoloading; progressively move first-party classes under a namespace.
4. **Extract config**: `.env` + phpdotenv for credentials.
5. **Add a test harness**: PHPUnit for new changes, even if legacy code stays untested.
6. **Set up CI**: GitHub Actions / GitLab CI to run `php -l` and PHPUnit on every push.
7. **Introduce Monolog** with `error_log` going to stderr + Apache error log.
