Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions ENHANCE_INTEGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Enhance Platform Integration
_Comprehensive documentation for the `software/enhance.php` checker_

---

## 1  What We’ve Built
`software/enhance.php` adds **real-time version monitoring** for the [Enhance](https://enhance.com) hosting platform to VersionCheck.
Key capabilities:

* Scrapes the public **Release Notes** page
`https://enhance.com/support/release-notes.html`
* Parses every core release (v9 → v12) including patch versions
(e.g. `12.6.0`, `12.5.1`, `12.0.30`)
* Detects which release is flagged **“Latest”** and records an _announcement_
link for notification e-mails
* Stores/updates one entry per **major.minor branch**
(`12.6`, `12.5`, `11.0`, …) keeping only the highest patch

The integration means administrators and subscribers will be alerted within
minutes of any new Enhance release.

---

## 2  How It Works

| Phase | Details |
|-------|---------|
| **Fetch** | `http::get()` (cURL) downloads the raw HTML. |
| **Parse** | `DOMDocument` iterates `<h1>` elements (each version header). |
| **Filter** | Non-core headers (`Appcd…`, `WHMCS…`, `PHP packages`) are ignored. |
| **Extract** | • Version number (`^\d+\.\d+\.\d+`) <br> • Branch = first two octets <br> • Release date from the first subsequent `<h3>` (ex “27th May 2025”) – converted to `Y-m-d H:i:s`. <br> • “Latest” determined by scanning sibling nodes for the word **Latest** (case-insensitive). |
| **Reduce** | All patch releases within the same branch are sorted by PATCH descending; only newest kept. |
| **Return** | Array structure consumed by `check.php`: ```php ['12.6' => ['version'=>'12.6.0','release_date'=>'2025-05-27 00:00:00','announcement'=>..., 'estimated'=>false], …]``` |

---

## 3&nbsp;&nbsp;Data Extracted

| Field | Example | Notes |
|------------------|--------------------------|-----------------------------------------|
| `software` | `enhance` (class name) | Stored automatically by core logic |
| `branch` | `12.6` | Major.Minor |
| `version` | `12.6.0` | Highest patch for branch |
| `release_date` | `2025-05-27 00:00:00` | Parsed; fallback = now + `estimated=1` |
| `announcement` | `https://enhance.com/support/release-notes.html#12.6.0` | Only present for branch marked **Latest** |
| `estimated` | `0`/`1` | `1` if date parsing failed |

---

## 4&nbsp;&nbsp;Setup Instructions

1. **Pull the code**
```bash
git fetch origin
git checkout feature/add-enhance-platform
```

2. **Verify file exists**
```
software/enhance.php
```

3. **Enable (optional)**
`public static $enabled = true;` by default.
Set to `false` to disable without deleting the file.

4. **Database**
No schema changes. `check.php` will auto-insert rows into `versions` and
`notifications` tables.

5. **Cron**
Ensure your existing cron that executes `check.php` remains active
(per installation guide). No additional jobs are required.

---

## 5&nbsp;&nbsp;Testing & Troubleshooting

### Quick CLI Test
```bash
php -r "
include 'software/enhance.php';
\$e = new enhance();
\$versions = \$e->get_versions(\$e->get_data());
print_r(array_slice(\$versions,0,3,true));
"
```

Expected trimmed output:
```
Array
(
[12.6] => Array
(
[version] => 12.6.0
[release_date] => 2025-05-27 00:00:00
[announcement] => https://enhance.com/support/release-notes.html#12.6.0
[estimated] =>
)
[12.5] => Array
(
[version] => 12.5.1
[release_date] => 2025-05-21 00:00:00
[estimated] =>
)
[12.4] => …
)
```

### Common Issues

| Symptom | Possible Cause | Resolution |
|---------|----------------|------------|
| **`RuntimeException` from `http::get`** | cURL blocked / TLS failure | Check outbound HTTPS, update CA bundle |
| **No versions detected** | HTML structure changed | Inspect page, update DOM traversal/regex |
| **Dates show “estimated”** | Release lacks `<h3>` date or new format | Raise issue; consider regex fallback |
| **Latest not flagged** | “Latest” label moved | Adjust sibling scan range (`$max_siblings_to_check`) |
| **Database errors on first run** | Missing `config.php` or wrong credentials | Follow install README – import SQL & configure PDO |

---

## 6&nbsp;&nbsp;Future Improvements

* **Caching / Rate-limit** – store fetched HTML to cut traffic & guard against
temporary site outages.
* **Unit tests** – mock HTML fixtures to detect parser breakage early.
* **Full historical capture** – store *all* patch versions, not just newest.
* **Security hardening** – sanitize/limit DOM parsing to reduce attack surface.
* **Graceful fallback** – if DOM parsing fails, attempt pure regex extraction.
* **Official API** – migrate to JSON endpoint if Enhance publishes one.
* **Notification granularity** – allow subscribers to opt into
major/minor/patch channels separately.

---

### Maintainer Notes
* Written for **PHP ≥8.0** (uses `JSON_THROW_ON_ERROR` in other checkers).
* Keep `$uri` constant if domain changes (e.g. `.html` vs no extension).
* Test after core panel redesigns – header hierarchy may shift.
150 changes: 150 additions & 0 deletions software/enhance.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<?php
require_once __DIR__ . '/abstract.php';
include_once(__DIR__ . '/../methods/http.php');

/*
Example structure of Enhance apt repository Packages file:

Package: ecp-core
Version: 12.6.0
Architecture: amd64
Maintainer: Enhance Ltd <backend@enhance.com>
Installed-Size: 87858
Depends: cron, curl, ecp-php56, ecp-php70, ecp-php71, ecp-php72, ecp-php73, ecp-php74, ecp-php80, ecp-php81, ecp-php82, ecp-php83, ecp-php84, libc6 (>= 2.34), libc6 (>= 2.38), libc6 (>= 2.39), libmilter1.0.1 (>= 8.14.1), libnss3-dev, libpam0g (>= 0.99.7.1), libssl3t64 (>= 3.0.0), linux-image-extra-virtual, openssh-server, openssl, quota, rsync, ufw, zlib1g (>= 1:1.1.4)
Conflicts: appcd
Replaces: appcd
Filename: pool/noble/ecp-core_12.6.0_amd64.deb
Size: 22096584
MD5sum: b8d084689177aa18b52ff7ee01443156
SHA1: b41084091113c5090f49a57f4f77b0f2d5774eec
SHA256: 4be9b14e6004debcdbc04819d07f2e78e2624760178cd7e72041722902f87704
Priority: optional
Description: [generated from Rust crate appcd]

Package: ecp-core
Version: 12.5.1
...
*/

class enhance extends SoftwareCheck
{
public static $name = 'Enhance Platform';
public static $vendor = 'Enhance';
public static $homepage = 'https://enhance.com/';
public static $type = 'apt';
public static $enabled = true;
var $uri = 'https://apt.enhance.com/dists/noble/main/binary-amd64/Packages';
var $release_uri = 'https://apt.enhance.com/dists/noble/Release';

function get_data()
{
// Get the Packages file
$packages_data = http::get($this->uri);

// Get the Release file for date information
try {
$release_data = http::get($this->release_uri);
} catch (Exception $e) {
// If we can't get the Release file, just use the Packages data
$release_data = '';
}

return [
'packages' => $packages_data,
'release' => $release_data
];
}

function get_versions($data = array())
{
if (empty($data) || !isset($data['packages']) || empty($data['packages'])) {
return array();
}

// Extract repository date from Release file if available
$repo_date = date("Y-m-d H:i:s"); // Default to current date/time
$estimated = true;

if (!empty($data['release'])) {
if (preg_match('/Date:\s+([^\n]+)/', $data['release'], $matches)) {
$date_str = trim($matches[1]);
if (($timestamp = strtotime($date_str)) !== false) {
$repo_date = date("Y-m-d H:i:s", $timestamp);
$estimated = false;
}
}
}

// Parse Packages file
$versions = array();
$branch_versions = array();
$latest_version = null;
$latest_version_full = null;

// Split the Packages file into individual package entries
$package_entries = explode("\n\n", $data['packages']);

foreach ($package_entries as $entry) {
// Check if this is an ecp-core package
if (strpos($entry, 'Package: ecp-core') === false) {
continue;
}

// Extract version
if (preg_match('/Version:\s+(\d+\.\d+\.\d+)/', $entry, $matches)) {
$version = $matches[1];

// Extract version components
$version_parts = explode('.', $version);
if (count($version_parts) < 3) {
continue;
}

// Determine branch (major.minor)
$branch = $version_parts[0] . '.' . $version_parts[1];
$patch = (int)$version_parts[2];

// Store in branch_versions for later processing
if (!isset($branch_versions[$branch])) {
$branch_versions[$branch] = array();
}

$branch_versions[$branch][] = array(
'version' => $version,
'patch' => $patch,
'info' => array(
'version' => $version,
'release_date' => $repo_date,
'estimated' => $estimated
)
);

// Track the latest version (highest version number)
if ($latest_version === null || version_compare($version, $latest_version_full, '>')) {
$latest_version = $branch;
$latest_version_full = $version;
}
}
}

// For each branch, keep only the highest patch version
foreach ($branch_versions as $branch => $branch_data) {
// Sort by patch version (descending)
usort($branch_data, function($a, $b) {
return $b['patch'] - $a['patch'];
});

// Keep only the highest patch version
if (!empty($branch_data)) {
$versions[$branch] = $branch_data[0]['info'];
}
}

// Mark only the highest version as the latest with an announcement link
if ($latest_version !== null && isset($versions[$latest_version])) {
$versions[$latest_version]['announcement'] = 'https://enhance.com/support/release-notes.html#' . $latest_version_full;
}

return $versions;
}
}