# Technical documentation — Sheriff

Evidence date: 2026-10-04.

Source: `git@bitbucket.org:overdrive/sheriff.git`, `master` at `6269872` (2025-05-20, Uriel_Balela). Clone used for this note. The scan-host directory was not on this machine. Secret values that appear in dormant test code are not copied here.

## What this repository is

A PHP site that wraps six Word-exported HTML documents in one layout. The office name in the layout is Sheriff for Wynberg North / Balju vir Wynberg-Noord.

The PHP stack is a cut-down copy of the Nemo class library. Public pages use `NemoBasic` only as a layout loader. The data, mail, SMS, and login helpers travel with the repository and are not called by those pages.

There is one branch, `master`. There is no README.

## Application structure

```text
index.php
immovable.php
movable.php
shipping.php
jurisdiction.php
contact.php
home.htm
immovable.htm
movable.htm
shipping.htm
jurisdiction.htm
contact.htm
layouts/Layout1.php
layouts/header.incl.php
css/styles.css
images/
js/
system.php
system.functions.inc.php
_nemo.basic.cls.php
_nemo.cls.php
_nemo.control.cls.php
_nemo.database.cls.php
_nemo.details.cls.php
_nemo.email.cls.php
_nemo.list.basic.cls.php
_nemo.list.cls.php
_nemo.menu.basic.cls.php
_nemo.menu.cls.php
_nemo.report.cls.php
```

Word sidecars (`*_files/`), Office documents, `Immovable.zip`, and `*20221128` snapshots sit beside that structure. They are not selected by the six scripts.

## Request path

1. The script creates an empty `$SystemSettings` array. Only `index.php` then writes `BASE_URL` for `localhost` and `dev.overdrive.co.za`.
2. `include_once("_nemo.basic.cls.php")` runs.
3. That file includes `system.php` first.
4. `system.php` turns on `display_errors`, sets `error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING)`, fills `$SystemSettings` from `$_SERVER`, and includes `system.functions.inc.php`.
5. `system.functions.inc.php` includes `_nemo.database.cls.php` and, when POST, GET, or cookies are non-empty, calls `localize()`.
6. `NemoBasic` is constructed. It copies `$SystemSettings`, scans `layouts/` and `modules/` into arrays, and constructs `NemoControl`. The line that would construct `NemoDatabase` is commented out.
7. The script sets `heading`, `activePage`, and `includes`.
8. `Display()` includes `layouts/header.incl.php` and then `layouts/Layout1.php` (`$this->Layout` defaults to `Layout1.php`).
9. `Layout1.php` also calls `include_once` on `layouts/header.incl.php`. The path matches the earlier include, so the header is not sent twice.
10. The layout prints chrome and `include_once`s the HTML file named in `$this->includes`.

`readDirectory()` uses `opendir`. The `modules` directory is not in git. `opendir` on a missing directory raises a warning. Warnings are excluded by `error_reporting`, so the public response does not show it, and the modules array stays empty. The methods that would include `Login.mod.inc.php` or `GMaps.mod.inc.php` are not called.

## Languages and frameworks

| Item | Evidence |
|---|---|
| PHP | All entry points and classes. Comments dated 24/11/2022 and commits in November 2022 and November 2023 call the work a PHP 8 upgrade |
| No Composer, npm, or other package manifest | No such file in `git ls-files` |
| Nemo class library | `_nemo.*.cls.php`. In-file comments name authors and dates from 2009–2012 (pj, wc, Stephen, Sebastian) |
| jQuery 1.4.4 | Header comment in `js/jquery.js` |
| jQuery UI 1.8.6 custom build | `js/jquery-ui-1.8.6.custom.min.js` |
| jQuery Cycle | `js/jquery.cycle/` |
| Word HTML | The six content files and the unused copies. Microsoft Office export markup (`MsoNormal`, `o:p`) |
| CSS | One project stylesheet, `css/styles.css`. No preprocessor |

The exact PHP version on the server is **Unknown / Requires Confirmation**. `6269872` exists because `E_STRICT` had become a deprecated constant. That constant's deprecation is a PHP 8.4 change. This inspection did not run the site.

## Runtime behaviour that matters

### BASE_URL

`system.php` sets:

```text
BASE_URL = {scheme}://{HTTP host} + script path with the filename removed
```

Scheme comes from the first token of `SERVER_PROTOCOL`, lower-cased (`http` from `HTTP/1.1`). It does not look at HTTPS termination in front of PHP. If the public site is HTTPS and PHP still sees `HTTP/1.1`, asset URLs are `http://`. **Inferred** from those two lines. Whether the live server presents HTTPS to PHP is **Unknown / Requires Confirmation**.

`index.php` writes `localhost/Sheriff` or `dev.overdrive.co.za/Sheriff` before the include. `system.php` replaces `BASE_URL` before `new NemoBasic()`. The switch does not affect the page.

`header.incl.php` prefixes CSS and script URLs with `BASE_URL`. When `system.php` has run, that prefix includes a scheme and host.

### Error reporting

`display_errors` is `1` on every request that loads `system.php`. Notices and warnings are hidden. Other errors can appear in the HTML. Provenance: **Implemented** in `system.php`.

### Request import

`localize()` is intended, by its comment, as a `register_globals` stand-in. It calls `gpc_extract($obj, $GLOBALS, $overrideDebug)`.

- `gpc_extract` declares two parameters. The third argument is extra.
- `$target` is not declared as a reference, so assignments inside the function do not write back to `$GLOBALS`.

On PHP 8, a user-defined function that receives too many arguments throws `ArgumentCountError`. Any request with a non-empty query string, POST body, or cookie jar reaches this call. A request with all three empty does not. This was read from the source and not executed. The deployed interpreter is **Unknown / Requires Confirmation**.

`stripslashes` is applied to values inside `gpc_extract`. Because the result is not written back, that call has no effect on `$_GET`, `$_POST`, or `$_COOKIE` either.

### Database

`system.php` calls `mysql_select_db` only inside `if (is_resource($db))`. Nothing in this repository assigns `$db` or `$DATABASE_SETTINGS`. The branch that would load `sysSettings` into `$SystemSettings` does not run. Commented messages ("Database is unavailable", "Database Connection has Failed") are not printed.

`NemoDatabase` uses `mysql_query`, `mysql_fetch_field`, and `mysql_error`. Those functions were removed with the old `mysql` extension (gone in PHP 7). Constructing `NemoDatabase` on PHP 8 would fail. The public pages do not construct it.

SQL fragments in the unused library name tables that are not created by any file in this repository: `sysSettings`, `sysLogin`, `sysSpam`, `tblEmailTemplate`, `tblMenuLevel1`, `tblMenuLevel2`, `tblProduct`, and a `sysUser` query inside `CheckSecurityLock`. No schema dump is in git.

`doQuery()` dies with the SQL text and `mysql_error()` output if a query fails. That path is unused by the six pages.

### Mail and SMS

`NemoEmail::Send()` and `SendFromDatabase()` call PHP `mail()`. The public pages do not call them.

At the bottom of `_nemo.email.cls.php`, a test block is gated by `$Action == "Test"`. The file sets `$Action` to `""` immediately above that test, so the block does not run on include. Inside it, a `NemoEmail` is constructed with a personal Gmail address and a plaintext sample password, and course-template names are referenced. Values omitted. Provenance: **Implemented**, dormant.

If `$_REQUEST['ajaxRequest']` is `GetTemplate`, the same file includes `system.php` again, queries `tblEmailTemplate` through `$xdb`, and `die`s with JSON. `$xdb` is only created when the database branch in `system.php` succeeds. On the tree as it stands, `$xdb` is unset and this branch fatals if it is hit. Provenance: **Implemented**. Not part of normal page navigation.

`SendSMS()` POSTs to `http://www.mymobileapi.com/api5/http5.aspx` with username, password, and a live flag taken from `$SystemSettings`. Those keys are never filled in this repository. `SendSMS()` is not called by the six pages. `do_post_request()` prints `error_get_last()` and `die`s when the HTTP wrapper fails.

### Sessions and cookies

`Login()` in `system.functions.inc.php` stores username, password, email, user id, and practice fields on `$_SESSION`, and sets cookies `celusername` and `celpassword` for 3600 seconds. The password value is the same value placed in the session. No public page calls `Login()`. No `session_start()` was found in the six scripts or in `system.php`. Provenance: **Implemented** in unused code.

### Analytics

`NemoBasic::GoogleAnalytics()` returns the legacy `ga.js` snippet for account `UA-20111494-1`. `Layout1.php` does not echo it. Provenance: **Implemented**, not rendered.

### Character set and document shape

The layout head declares `iso-8859-1`. Each content file is a complete Word HTML document included inside `<div class='Content'>`, so the response contains nested `html` / `head` / `body` markup. Provenance: **Implemented**.

Page titles the visitor is given by the layout:

| Script | `<title>` |
|---|---|
| `index.php` | Sheriff :: Home |
| `immovable.php` | Sheriff :: Immovable |
| `movable.php` | Sheriff :: Movable |
| `shipping.php` | Sheriff :: Shipping |
| `jurisdiction.php` | Sheriff :: Jurisdiction |
| `contact.php` | Sheriff :: Contact Us |

`shipping.htm` also contains `<title>SALE OF YACHT "MONDINA"</title>` inside the included document.

## Front end

`css/styles.css` lays out a 1000px column (`.Header`, `.MenuCenter`, `.Banner`, `.Content`). The menu bar is `#989898`. The active item and hover use `#636363`. The footer is absolutely positioned at `bottom: 0` with height 196px. `.Content` pads the bottom by 250px. Footer blocks use `images/FooterShadow.png`.

The header also links files that are not in the repository:

- `images/icon.ico` (the tree has `favicon.ico` at the root, not this path)
- `css/ie.lamp.css` when `SERVER_NAME` is `lamp`
- `css/ie.live.css` otherwise, inside an IE conditional comment
- `css/passwordstrength.css`
- `css/smoothness/jquery-ui-1.8.6.custom.css`

`SERVER_NAME == "lamp"` is the old Nemo local-host check. This repository's `index.php` switch talks about `localhost` and `dev.overdrive.co.za`, not `lamp`. A response generated with a normal public host name includes the `ie.live.css` link inside the IE conditional. Provenance: **Implemented**.

Scripts linked from the header are listed in `features.md`. jQuery on these pages is 1.4.4. The notice HTML does not call it.

## Authentication

The six URLs do not authenticate. There is no login form in the repository.

Unused library behaviour, for anyone who later instantiates `Nemo` or calls `Login()`:

- Missing `$_SESSION[USER]` redirects and exits.
- `setSecurityGroup()` writes a security-group id onto `$SystemSettings[USER]`.
- `CheckSecurityLock()` counts recent rows in `sysLogin` for failed and successful passwords and can send `NemoEmail`. It is not called by the six pages.

## Background work, queues, storage, monitoring

None. No cron script, queue worker, object store, or monitoring config is in the tree. `pdfEncrypt()` requires `fpdi/FPDI_Protection.php`, which is not in the repository, and nothing calls `pdfEncrypt()`.

## Deployment and environment

No Dockerfile, CI file, web-server config, or `.env` is in git.

`index.php` records two names that were considered hosts: `localhost` (base path `Sheriff`) and `dev.overdrive.co.za` (base path `Sheriff`). Those assignments are overwritten, as described above. The footer publishes `www.sheriff.co.za`. Which host actually runs `6269872` is **Unknown / Requires Confirmation**.

Commit `089abd8` (2023-11-14, message `CXopy files from prod to repo`) is the last time `immovable.htm` and `movable.htm` changed. The message says production was copied into git. It does not name the server.

`.gitignore` is the generic Atlassian example (node_modules, class files, logs, IDE files). It does not ignore the Word sidecars or the dated PHP snapshots, and those files are committed.

## Security notes from the tree

These are observations, not a pentest.

| Observation | Where | Reached by a normal page view? |
|---|---|---|
| `display_errors` is on | `system.php` | Yes |
| `mysql_*` and `eregi` remain in library code | `_nemo.database.cls.php`, `isValidEmail()` | No, unless that code is called |
| SQL is concatenated in unused helpers (`GetTemplate` appends `TemplateID` after `qs()`, but other helpers interpolate ids directly) | `_nemo.email.cls.php`, `system.functions.inc.php` | No on the six pages |
| `doQuery()` can print the failing SQL | `_nemo.database.cls.php` | No on the six pages |
| Dormant test block contains a personal email address and a sample password | `_nemo.email.cls.php` | No, while `$Action` is `""` |
| `Login()` would store a password in a cookie | `system.functions.inc.php` | No, not called |
| SMS credentials would be read from settings if a database were connected | `SendSMS()` | No |
| Extra argument to `gpc_extract` on any request that has a query, body, or cookie | `system.functions.inc.php` | Yes, for those requests, if the interpreter rejects extra arguments |
| Staff names, email addresses, a cell number, and office telephones are in the HTML on purpose | `contact.htm`, `home.htm`, `shipping.htm`, `immovable.htm` | Yes. They are the published directory |

No password, API key, or database password is assigned in the files the six pages execute.

## Development and testing

No PHPUnit, no fixture, no test script, and no CI configuration is in the repository.

The practical content workflow shown by git is: edit the Word HTML (or the footer PHP) and commit. PHP changes in history are compatibility edits, not new pages.

## Dependencies that are not this product

Celestis Academy branding, FSP Exchange links, course email templates, and practice-login fields are inside `NemoBasic`, `Nemo`, and `system.functions.inc.php`. They are leftovers from the library's earlier use. The sheriff layout does not call those methods. Provenance: **Implemented** in unused methods. A shared product with a Celestis system is **Unknown / Requires Confirmation** and is not required to explain the six pages.
