HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //home/ezoshosting.com/scripts/price-sync.php
#!/usr/local/lsws/lsphp74/bin/php
<?php

declare(strict_types=1);

const PRICE_SOURCE_URL = 'https://support.ezoshosting.com/products/';
const DEFAULT_TARGET_PATH = '/home/ezoshosting.com/public_html/assets/data/prices.json';
const DEFAULT_LOG_PATH = '/home/ezoshosting.com/logs/price-sync.log';
const USER_AGENT = 'EZOS-PriceSync/1.0';
const HTTP_TIMEOUT_SECONDS = 15;

$targetPath = isset($argv[1]) && $argv[1] !== '' ? $argv[1] : DEFAULT_TARGET_PATH;
$logFromEnvironment = getenv('PRICE_SYNC_LOG');
$logPath = isset($argv[2]) && $argv[2] !== ''
    ? $argv[2]
    : ($logFromEnvironment !== false && $logFromEnvironment !== '' ? $logFromEnvironment : DEFAULT_LOG_PATH);
$temporaryPath = null;

set_error_handler(static function (int $severity, string $message, string $file, int $line): bool {
    if (!(error_reporting() & $severity)) {
        return false;
    }
    throw new ErrorException($message, 0, $severity, $file, $line);
});

function writeLog(string $logPath, string $level, string $message): void
{
    $line = sprintf('[%s] %s %s%s', gmdate('Y-m-d\TH:i:s\Z'), $level, $message, PHP_EOL);
    @file_put_contents($logPath, $line, FILE_APPEND | LOCK_EX);
}

function fetchSource(string $url): string
{
    if (extension_loaded('curl')) {
        $handle = curl_init($url);
        if ($handle === false) {
            throw new RuntimeException('Could not initialize cURL.');
        }
        curl_setopt_array($handle, array(
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CONNECTTIMEOUT => HTTP_TIMEOUT_SECONDS,
            CURLOPT_TIMEOUT => HTTP_TIMEOUT_SECONDS,
            CURLOPT_USERAGENT => USER_AGENT,
            CURLOPT_HTTPHEADER => array('Accept: text/html,application/xhtml+xml'),
            CURLOPT_ENCODING => '',
        ));
        $body = curl_exec($handle);
        $curlError = curl_error($handle);
        $statusCode = (int) curl_getinfo($handle, CURLINFO_HTTP_CODE);
        curl_close($handle);

        if ($body === false) {
            throw new RuntimeException('Source request failed: ' . $curlError);
        }
        if ($statusCode < 200 || $statusCode >= 300) {
            throw new RuntimeException('Source request returned HTTP ' . $statusCode . '.');
        }
        if ($body === '') {
            throw new RuntimeException('Source response was empty.');
        }
        return $body;
    }

    $context = stream_context_create(array(
        'http' => array(
            'method' => 'GET',
            'timeout' => HTTP_TIMEOUT_SECONDS,
            'ignore_errors' => true,
            'header' => "User-Agent: " . USER_AGENT . "\r\nAccept: text/html,application/xhtml+xml\r\n",
        ),
    ));
    $body = file_get_contents($url, false, $context);
    if ($body === false || $body === '') {
        throw new RuntimeException('Source request failed or returned an empty response.');
    }
    $statusCode = 0;
    if (isset($http_response_header) && preg_match('/^HTTP\/\S+\s+(\d{3})\b/', $http_response_header[0], $match)) {
        $statusCode = (int) $match[1];
    }
    if ($statusCode < 200 || $statusCode >= 300) {
        throw new RuntimeException('Source request returned HTTP ' . ($statusCode ?: 'unknown') . '.');
    }
    return $body;
}

/** @return array<int, array{value: float, offset: int}> */
function findDollarAmounts(string $html): array
{
    $result = preg_match_all(
        '/\$\s*([0-9]+(?:,[0-9]{3})*(?:\.[0-9]{1,2})?)(?![0-9.])/',
        $html,
        $matches,
        PREG_OFFSET_CAPTURE
    );
    if ($result === false) {
        throw new RuntimeException('Dollar amount regex failed.');
    }
    $amounts = array();
    foreach ($matches[1] as $index => $capture) {
        $numeric = str_replace(',', '', $capture[0]);
        if (is_numeric($numeric)) {
            $amounts[] = array('value' => (float) $numeric, 'offset' => (int) $matches[0][$index][1]);
        }
    }
    return $amounts;
}

/** @return int[] */
function findCategoryOffsets(string $html, string $pattern): array
{
    $result = preg_match_all($pattern, $html, $matches, PREG_OFFSET_CAPTURE);
    if ($result === false) {
        throw new RuntimeException('Category regex failed.');
    }
    return array_map(static function (array $capture): int {
        return (int) $capture[1];
    }, $matches[0]);
}

/**
 * @param int[] $categoryOffsets
 * @param array<int, array{value: float, offset: int}> $amounts
 * @return array<int, array{amount_index: int, distance: int}>
 */
function nearbyCandidates(array $categoryOffsets, array $amounts): array
{
    $candidates = array();
    foreach ($categoryOffsets as $categoryOffset) {
        foreach ($amounts as $amountIndex => $amount) {
            $distance = abs($amount['offset'] - $categoryOffset);
            if ($distance <= 2500) {
                $candidates[] = array('amount_index' => $amountIndex, 'distance' => $distance);
            }
        }
    }
    usort($candidates, static function (array $left, array $right): int {
        return $left['distance'] <=> $right['distance'];
    });
    return $candidates;
}

/** @return array{managed_local_ai_from: float, open_source_hosting_from: float} */
function extractPrices(string $html): array
{
    $amounts = findDollarAmounts($html);
    $localOffsets = findCategoryOffsets($html, '/(?:Managed\s+Local\s+AI|managed-local-ai)/i');
    $hostingOffsets = findCategoryOffsets($html, '/(?:Open\s+Source\s+Hosting|open-source-hosting)/i');
    $localCandidates = nearbyCandidates($localOffsets, $amounts);
    $hostingCandidates = nearbyCandidates($hostingOffsets, $amounts);
    $bestPair = null;
    $bestScore = PHP_INT_MAX;

    foreach ($localCandidates as $localCandidate) {
        foreach ($hostingCandidates as $hostingCandidate) {
            if ($localCandidate['amount_index'] === $hostingCandidate['amount_index']) {
                continue;
            }
            $score = $localCandidate['distance'] + $hostingCandidate['distance'];
            if ($score < $bestScore) {
                $bestScore = $score;
                $bestPair = array($localCandidate['amount_index'], $hostingCandidate['amount_index']);
            }
        }
    }

    if ($bestPair !== null) {
        return array(
            'managed_local_ai_from' => $amounts[$bestPair[0]]['value'],
            'open_source_hosting_from' => $amounts[$bestPair[1]]['value'],
        );
    }
    if (count($amounts) !== 2) {
        throw new RuntimeException(
            'Could not map prices to categories; fallback requires exactly 2 dollar amounts, found ' . count($amounts) . '.'
        );
    }
    $values = array($amounts[0]['value'], $amounts[1]['value']);
    sort($values, SORT_NUMERIC);
    if ($values[0] === $values[1]) {
        throw new RuntimeException('Fallback amounts are identical and cannot be assigned by magnitude.');
    }
    return array('managed_local_ai_from' => $values[1], 'open_source_hosting_from' => $values[0]);
}

/** @param array{managed_local_ai_from: float, open_source_hosting_from: float} $prices */
function validatePrices(array $prices): void
{
    $localAi = $prices['managed_local_ai_from'];
    $hosting = $prices['open_source_hosting_from'];
    if (!is_finite($localAi) || $localAi < 100 || $localAi > 5000) {
        throw new RuntimeException('Managed Local AI price failed the 100..5000 sanity range.');
    }
    if (!is_finite($hosting) || $hosting < 1 || $hosting > 500) {
        throw new RuntimeException('Open Source Hosting price failed the 1..500 sanity range.');
    }
}

try {
    $html = fetchSource(PRICE_SOURCE_URL);
    $prices = extractPrices($html);
    validatePrices($prices);
    $payload = array(
        'updated' => gmdate('Y-m-d\TH:i:s\Z'),
        'currency' => 'USD',
        'managed_local_ai_from' => $prices['managed_local_ai_from'],
        'open_source_hosting_from' => $prices['open_source_hosting_from'],
    );
    $json = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION);
    if ($json === false) {
        throw new RuntimeException('Could not encode price JSON: ' . json_last_error_msg());
    }
    $json .= PHP_EOL;

    $targetDirectory = dirname($targetPath);
    if (!is_dir($targetDirectory) || !is_writable($targetDirectory)) {
        throw new RuntimeException('Target directory does not exist or is not writable: ' . $targetDirectory);
    }
    $temporaryPath = tempnam($targetDirectory, '.prices.');
    if ($temporaryPath === false) {
        throw new RuntimeException('Could not create a temporary file in the target directory.');
    }
    $bytesWritten = file_put_contents($temporaryPath, $json, LOCK_EX);
    if ($bytesWritten === false || $bytesWritten !== strlen($json)) {
        throw new RuntimeException('Could not write the complete temporary JSON file.');
    }
    if (!chmod($temporaryPath, 0644)) {
        throw new RuntimeException('Could not set permissions on the temporary JSON file.');
    }
    if (!rename($temporaryPath, $targetPath)) {
        throw new RuntimeException('Could not atomically replace the target JSON file.');
    }
    $temporaryPath = null;

    writeLog(
        $logPath,
        'OK',
        sprintf(
            'updated prices: managed_local_ai_from=%.2f open_source_hosting_from=%.2f target=%s',
            $prices['managed_local_ai_from'],
            $prices['open_source_hosting_from'],
            $targetPath
        )
    );
    exit(0);
} catch (Throwable $error) {
    if ($temporaryPath !== null && is_file($temporaryPath)) {
        @unlink($temporaryPath);
    }
    writeLog($logPath, 'ERROR', $error->getMessage());
    exit(1);
}