# demo_youportal — Pre-Migration Technical Audit

**Audit date:** 2026-04-10
**Target path:** `/var/www/html/demo_youportal/`
**Purpose:** Comprehensive assessment ahead of migration to a production deployment.

---

## 1. Tech Stack

| Layer | Detail |
|---|---|
| **Language** | PHP 7.4.33 (CLI verified). No `php` constraint declared in `composer.json` — risk on PHP 8 upgrade. |
| **Framework** | None. Homegrown MVC-lite. PSR-4 in `composer.json` only maps `Model\\ → app/Model/`; the real loader is `controller/spl_autoload_register.php`. |
| **Frontend** | jQuery + vanilla JS, server-rendered PHP templates with `<wwbn:plugin>BODY</wwbn:plugin>` placeholder substitution. ~419 JS files in source tree. |
| **Node services** | Single sidecar **chat module** (`server.js` / `package.json`): Express 4.15, Socket.io 1.7 (very old), `mysql` + `mysql2`, `axios`. |
| **Composer deps** | Stripe `^17.2`, SendGrid `^8.1`, Guzzle `^6.5` (EOL), Google APIClient `^2.7`, DomPDF `^3.1`, vlucas/phpdotenv `^5.6`, Facebook Graph SDK `^5.7` (EOL/deprecated), Vimeo, Dailymotion, Twitter (abraham `^1.0`), LinkedIn, Tumblr, GeoIP2, didom 1.18, paragonie/random_compat. |
| **Vendor / node_modules** | `vendor/` 222 MB (committed in tree); `node_modules/` 30 MB. |

## 2. Architecture

- **Single entry point**: `index.php` — handles session, multi-tenant domain resolution, template selection, and dispatch.
- **Routing**: `.htaccess` rewrites clean URLs (`/Search/...`, `/Blog/...`, `/watch/...`, `/meet/...`) to `index.php?mid={module}&...`. Per-page logic injected via `*_script.php` files (`home_script.php`, `blog_script.php`, `search_script.php`, `events_script.php`, `media_gallery_script.php`, `contactus_script.php`) — these are PHP-templated JavaScript blobs glued into the response.
- **Controllers**: `controller/` — **96 subdirectories**, autoloaded via `spl_autoload_register.php`.
- **Domain classes**: `classes/` — **~120 top-level subdirectories** (domain-organized: `auth`, `billing`, `blog`, `chat`, `events`, `iptv`, `jwt`, `media`, `openai`, `sdba`, `stripe-php`, `stripe-php6`, etc.).
- **Models**: `models/` plus the unused PSR-4 `app/Model/` namespace.
- **API**: `api/json/index.php` is a `type`+`api_key`-keyed REST dispatcher; legacy endpoints under `api/searchmercials/`, `api/mediaSearchmercials/`. A 1.3 MB plain-text `apiurl.txt` exists at the root.
- **MVC adherence**: Loose. View/controller/model boundaries blur in `*_script.php` and `platform/` pages, where SQL, HTML, and JS routinely live in the same file.

## 3. Directory Structure & Counts

- **Total source files**: 5,064 PHP files outside `vendor/`/`node_modules/`.
- **classes/**: 180 subdirectories (incl. nested).
- **controller/**: 96 subdirectories.
- **Top level**: `index.php`, `r.php`, `server.js` (Node chat), `ai/`, `api/`, `classes/`, `controller/`, `iptv/`, `meet/`, `models/`, `myaccount/`, `notifi/`, `platform/`, `push/`, `services/`, `template/`, `vendor/`, `website/`, `node_modules/`, plus all the `*_script.php` page handlers and several stray files (`appdoc.php`, `apptest.php`, `sample.php`, `testing.php`, `webpliance_checker.php`, `ded7376.log`).
- **Documentation**: `Documentation/`, `info.html`, `info_php/`, `README.md`.

## 4. Subsystems

| Module | Location | Notes |
|---|---|---|
| **Auth** | `classes/auth/`, `platform/authentication/`, `platform/authentication_git/` | **Two parallel auth trees** (`authentication` and `authentication_git`); session-based (`$_SESSION['uid']`); 2FA folder present (`classes/2fa/`); social OAuth (FB/LI/Twitter/MS/Dailymotion). |
| **JWT** | `classes/jwt/` | Firebase JWT lib present but `prepare()` count in classes is 4 — JWT appears barely wired in. |
| **Billing** | `classes/billing/`, `classes/stripe-php/`, `classes/stripe-php6/`, `classes/wwbn_account_balance/`, `services/` | **Two Stripe SDK trees** in `classes/`, plus the `stripe/stripe-php` Composer package — **three Stripe code paths**. |
| **Chat** | `classes/chat/`, `server.js`, `controller/chat_module/` | Node.js + Socket.io 1.7 sidecar with raw `mysql` driver. |
| **Media / Gallery** | `classes/media/`, `classes/media_library/`, `classes/gallery/`, `media_gallery_script.php` | Includes `Media.class.php.orig` backup beside live class. |
| **AI** | `ai/`, `classes/openai/`, `classes/writing_assistant/` | OpenAI ChatGPT integration with streaming + audio transcription. |
| **Video conferencing** | `meet/` | Jitsi-style iframe embed. |
| **IPTV** | `iptv/`, `classes/iptv/` | M3U/RSS playlist player (mokoiptv lib). |
| **Notifications** | `notifi/`, `push/`, `onesignal.php` | OneSignal push. |
| **Directory / Marketplace** | `classes/directory/`, `classes/listing/`, `classes/local_listing/`, `classes/searchmercials/` | Multi-tenant directory/listings core. |
| **Other** | Reservation, Events, Newsfeed, Blog, Petregistry, Vehicle, Reviews, Voting, Bookmark, Coupon, Ticket-system, Webmail, QR, Securimage CAPTCHA, PHPMailer, SwiftMailer, php-zip-master, phpseclib. |

## 5. Database Layer

- **Custom query builder/ORM** at `classes/sdba/sdba.php` (`Sdba::table()`, `Sdba::db()->query()`), wrapping MySQLi.
- **Connection config**: `classes/sdba/sdba_config.php` — **DB credentials hardcoded as static class properties** (`dbuser='ostv'`, `dbpass='w2e3r4t5'`), duplicating values from `.env`.
- **Prepared statements**: only **4 occurrences of `prepare(`** across `classes/` (in `securimage` and one `auth/Database.class.php`). The rest of the codebase uses string-built SQL — `Sdba::db()->query("SELECT ... WHERE x = '".$var."'")`.
- **Sanitation pattern**: `$globalclass->clean()` is used inconsistently; the SDBA layer logs queries but does not enforce parameter binding.
- **Multi-DB**: code references multiple databases (`demo_youportal`, `searchmercials`, `help`, `searchads-db`) — migration must move all four.

## 6. Security Posture

- **`display_errors`**: forced ON at `index.php:3` — `ini_set('display_errors', 1)`. `error_reporting(1)` (oddly only `E_ERROR`).
- **DEBUG/DEV flags**: `.env` sets `DEVELOPMENT=true`, `DEBUG=true`.
- **SQL injection**:
  - `index.php:129-131` interpolates `$domain` and `$subdomain` (derived from `$_SERVER['SERVER_NAME']`) directly into queries on `domain_names` / `domain_names_sites`. `SERVER_NAME` is partially controllable via Host header.
  - 8 grep hits for `WHERE … = "'.$_GET/POST/REQUEST` across `platform/demographics/jstree_server.php`, `platform/services/.../PetRegistryManager/...`, `platform/module/tubes/pages/media.php`, `platform/module/CampaignManager/pages/media.php` — these are unparameterized user input in SQL.
  - The pattern is almost certainly more widespread; the regex was conservative.
- **`eval()`**: present in **20+ PHP files**, including `platform/components/foot.php`, `website_js.php`, `platform/services/websites/analytics/inc/*.php`, `platform/module/RankPayManager/js.php`, `platform/services/tools/rankpay/js.php`, `class.phpmailer.php` (vendored). Several feed user-related strings into `eval()` — needs case-by-case review.
- **Auth model**: session-based (`$_SESSION['uid']`), no CSRF tokens visible at the entry point. JWT lib bundled but unused for the main flow.
- **Forced login redirect** in `index.php:179-184` is conditional on a `parsedomain.php` flag — fail-open if that flag isn't set.

## 7. Environment & Secrets

`.env` is **present in the project directory** with **live secrets**:

```
DB_PASS=w2e3r4t5
OPENAI_APIKEY=youportalf8KatCch6fKl6gM0gWO1pBQV2DI99bzoSqrdAfjy2Uvx4ON40dAJ3GOGQAKd0UroHshtKvaaC3j0AQuDRmyWPVM9nPunQkbvlZZRqz3h201OpKaSfEXc83Z
SAP_API=d7fa393d-5ffb-45d8-8a2c-6978577f6e4c
CF_ACCT_ID=6a30cb8f58313c05fdc6cb176d4af672
SEARCHAPIKEY=d197f63c-e57a-42de-bdae-921a2e3fc647
DEVELOPMENT=true
DEBUG=true
```

The same DB password is **also hardcoded** in `classes/sdba/sdba_config.php:8`. Any of these keys, if they were ever pushed to the production target without rotation, must be **rotated before migration**.

## 8. Differences From a Typical Production Deployment

- **Total directory size: 20 GB** — far larger than the ~5,000 PHP source files would justify. Most of the bulk lives outside `vendor/` (222 MB) and `node_modules/` (30 MB), so it's media/uploads/logs/backup data co-located in the web root.
- `vendor/` and `node_modules/` are **both committed in-tree** rather than installed at deploy time.
- **Backup/.orig/.bak files everywhere** — at least 50+ found, including security-sensitive ones:
  - `classes/auth/Account.class (copy).php`
  - `classes/auth/Account.class.php.orig`
  - `classes/media/Media.class.php.orig`
  - `platform/authentication/includes/account/signup.php.bak`
  - `platform/authentication/includes/account/oauth.php.bak`
  - `platform/authentication/includes/linkedinoauth/login_with_linkedin.php.bak`
  - `platform/authentication/includes/dailymotionoauth/authorization.php.backup-11132015` (yes, from 2015)
  - `robots.php_backup`
  - `platform/services/dashboard/dashboard_backup20210901.php`
  - `platform/administration/templates/pages/template_list_backup.php`
- **Date-stamped class duplicates** in `classes/`: `announcement_06162020`, `blog_062020`, `events_07102020`, `news_06042020`, `petregistry_26052020`, `product_05222020`, `service_05232020`, `solution_05232020`, `testimonial_02062020`, `vehicle_01062020`, `voting_03062020`, `voting_05182020`. These are old versions that were renamed instead of deleted — likely autoloaded if their class names collide.
- **Parallel module trees**: `platform/authentication/` AND `platform/authentication_git/`; `classes/stripe-php/` AND `classes/stripe-php6/`.
- **Stray test/debug files in webroot**: `appdoc.php`, `apptest.php`, `sample.php`, `testing.php`, `webpliance_checker.php`, `ded7376.log` (writable log file in docroot).
- **Sibling `demo_youportal_bloated/`** — even larger (32 GB). This `demo_youportal` is already the "trim" version.

## 9. Migration-Blocking Issues

1. **Secrets in repo** — must be rotated and removed from the deployable artifact.
2. **PHP 7.4 lock-in** — Composer doesn't pin a PHP version. Stripe `^17.2`, DomPDF `^3.1`, and `phpdotenv ^5.6` all require PHP 7.4+ but Stripe 17 and DomPDF 3 prefer PHP 8.1+. Test the dependency tree under the production PHP version before cutover.
3. **Deprecated/EOL deps** — Guzzle 6 (EOL), Facebook Graph SDK 5 (EOL), Socket.io 1.7 (8 years old), abraham/twitteroauth 1.0.
4. **Two auth trees** (`authentication`, `authentication_git`) — confirm which is live before deploying; `.bak` files in `authentication/includes/account/signup.php.bak` etc. could be web-served if Apache lacks a `.bak` deny rule.
5. **Hardcoded DB credentials** in `classes/sdba/sdba_config.php` will silently override `.env` — change once, and it still leaks via the static config.
6. **Date-versioned duplicate class dirs** may collide via the autoloader — production may load the wrong class.
7. **20 GB bulk** is mostly non-source. Need to identify what's user data vs. cruft before sync; rsync of the whole tree will move backups, logs, and media wholesale.
8. **`eval()` usage in production code paths** (analytics, rankpay, foot.php) — code review required before exposing to internet.
9. **`display_errors`/`DEBUG`** must be flipped off; `error_reporting(1)` is a bug regardless (likely meant `E_ALL`).
10. **No tests visible** — `apptest.php` and `testing.php` are scratch files, not a test suite. Migration verification will be manual.

## 10. Disk Usage

- `demo_youportal/` total: **20 GB**
- `vendor/`: 222 MB
- `node_modules/`: 30 MB
- Implied content (uploads, media, logs, backups): **~19.7 GB** outside dependency dirs

---

## Bottom Line

`demo_youportal` is a **large, long-lived, homegrown PHP 7.4 multi-tenant portal platform** (~5k source PHP files, ~120 domain modules, ~96 controllers) carrying years of accumulated technical debt: parallel auth trees, three Stripe code paths, ~12 date-stamped "old version" class directories, ~50+ `.bak`/`.orig` files (some in auth code), `eval()` scattered through production paths, near-zero use of prepared statements, and `display_errors`/`DEBUG` forced on. The `.env` checked into the tree contains a live OpenAI key, multiple API keys, and a DB password that is **also** hardcoded in `classes/sdba/sdba_config.php`. Of the 20 GB total, ~98% is non-source content co-located with the application.

**This is not safely "lift and shift" material.** A clean migration requires (1) secret rotation, (2) deciding which of the duplicated subsystems is canonical, (3) stripping `.bak`/`.orig`/date-stamped backups out of the deployable artifact, (4) separating user data/media from code, (5) deciding the target PHP version and re-resolving Composer, and (6) at minimum a security pass on `eval()` and SQL-interpolation hotspots before the new instance is internet-facing.

## Red Flags

| # | Severity | Issue | Location |
|---|---|---|---|
| 1 | **CRITICAL** | Live secrets (OpenAI key, DB password, API keys) committed in `.env` | `/.env` |
| 2 | **CRITICAL** | DB credentials hardcoded as static class properties — will silently override env | `classes/sdba/sdba_config.php:7-9` |
| 3 | **CRITICAL** | Near-zero prepared statements (4 across `classes/`); SQL built by string interpolation throughout | `classes/sdba/`, all of `platform/`, `index.php:129-131` |
| 4 | **HIGH** | `eval()` in production code paths — analytics, rankpay, foot.php, website_js.php | 20+ files; sample: `platform/components/foot.php`, `platform/services/websites/analytics/inc/*.php` |
| 5 | **HIGH** | `display_errors=1`, `DEBUG=true`, `DEVELOPMENT=true` | `index.php:3-5`, `.env:14-15` |
| 6 | **HIGH** | Backup files in auth code paths potentially webroot-accessible | `platform/authentication/includes/account/signup.php.bak`, `oauth.php.bak`, `login_with_linkedin.php.bak` |
| 7 | **HIGH** | Two parallel auth trees with unclear ownership | `platform/authentication/`, `platform/authentication_git/` |
| 8 | **HIGH** | 12+ date-stamped "old version" class directories autoloaded alongside live ones | `classes/blog_062020/`, `classes/events_07102020/`, `classes/petregistry_26052020/`, etc. |
| 9 | **HIGH** | Three Stripe integration paths | Composer `stripe/stripe-php@^17`, `classes/stripe-php/`, `classes/stripe-php6/` |
| 10 | **MEDIUM** | `vendor/` and `node_modules/` committed in-tree (222 MB + 30 MB) | `/vendor`, `/node_modules` |
| 11 | **MEDIUM** | Composer has no PHP version pin; deps include EOL libs (Guzzle 6, FB Graph SDK 5, Socket.io 1.7) | `composer.json`, `package.json` |
| 12 | **MEDIUM** | 20 GB total directory; ~19.7 GB is non-source/non-deps (media, logs, backups co-located with code) | root |
| 13 | **MEDIUM** | Stray test/debug files at webroot (`apptest.php`, `testing.php`, `sample.php`, `webpliance_checker.php`, `ded7376.log`) | `/` |
| 14 | **MEDIUM** | `error_reporting(1)` reports only `E_ERROR` — likely a typo; warnings/notices silently dropped | `index.php:5` |
| 15 | **MEDIUM** | Session-based auth with no visible CSRF protection at the entry point; JWT lib bundled but unused | `index.php`, `classes/jwt/` |
| 16 | **MEDIUM** | Multi-DB setup (`demo_youportal`, `searchmercials`, `help`, `searchads-db`) — migration must move all 4 | `.env:3-6` |
| 17 | **LOW** | `controller/spl_autoload_register.php` is the real autoloader; `composer.json` PSR-4 only maps unused `Model\\` namespace | `composer.json:2-6` |
| 18 | **LOW** | Sibling `demo_youportal_bloated/` (32 GB) — confirm which is the source of truth before migrating either | `/var/www/html/` |
