Secure
Version.php
← Back to Folder Raw Code
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
<?php
if (php_sapi_name() !== 'cli') {
    exit('This script can only be run from the command line.');
}
$scriptDir = dirname(dirname(__FILE__));
$indexerFilesDir = $scriptDir;
$configFile = $indexerFilesDir . '/config.json';
class VersionChecker {
    private $indexerFilesDir;
    private $configFile;
    private $versionDb;
    private $versionPdo = null;
    private $primaryUrl = 'https://raw.githubusercontent.com/5q12-ccls/5q12-s-Indexer/refs/heads/main/repo';
    private $fallbackUrl = 'https://ccls.icu/src/repositories/5q12-indexer/main/repo/?view=raw';
    public function __construct($indexerFilesDir, $configFile) {
        $this->indexerFilesDir = $indexerFilesDir;
        $this->configFile = $configFile;
        $this->versionDb = $indexerFilesDir . '/cache/version.sqlite';
        $this->initializeVersionDb();
    }
    private function getStoredVersionData() {
        if (!$this->versionPdo) {
            return null;
        }
        try {
            $stmt = $this->versionPdo->prepare("SELECT value, cached_at FROM version_info WHERE key = 'remote_version_info'");
            $stmt->execute();
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            if ($result) {
                $data = json_decode($result['value'], true);
                $data['cached_at'] = $result['cached_at'];
                return $data;
            }
            return null;
        } catch (Exception $e) {
            echo "Error reading stored version data: " . $e->getMessage() . "\n";
            return null;
        }
    }
    private function compareVersions($currentVersion, $latestVersion) {
        if (version_compare($currentVersion, $latestVersion, '<')) {
            echo "Update available: $currentVersion -> $latestVersion\n";
        } elseif (version_compare($currentVersion, $latestVersion, '>')) {
            echo "Current version is newer than remote: $currentVersion > $latestVersion\n";
        } else {
            echo "Versions match: $currentVersion = $latestVersion\n";
        }
    }
    private function initializeVersionDb() {
        $cacheDir = $this->indexerFilesDir . '/cache';
        if (!is_dir($cacheDir)) {
            @mkdir($cacheDir, 0777, true);
        }
        try {
            $this->versionPdo = new PDO('sqlite:' . $this->versionDb);
            $this->versionPdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->versionPdo->exec("CREATE TABLE IF NOT EXISTS version_info (
                key TEXT PRIMARY KEY,
                value TEXT NOT NULL,
                cached_at INTEGER NOT NULL
            )");
            if (file_exists($this->versionDb)) {
                @chmod($this->versionDb, 0666);
            }
        } catch (Exception $e) {
            echo "Version database initialization error: " . $e->getMessage() . "\n";
            $this->versionPdo = null;
        }
    }
    public function checkAndUpdateVersion() {
        echo "Starting version check...\n";
        $currentVersion = $this->getCurrentVersion();
        echo "Current version from config.json: " . ($currentVersion ?: 'Not found') . "\n";
        $storedVersionData = $this->getStoredVersionData();
        $storedCurrentVersion = $storedVersionData ? $storedVersionData['current_version'] : null;
        echo "Stored current version from database: " . ($storedCurrentVersion ?: 'Not found') . "\n";
        if ($currentVersion && $storedCurrentVersion && $currentVersion === $storedCurrentVersion) {
            echo "Config version matches database version - no remote check needed\n";
            echo "Using cached remote version: " . ($storedVersionData['remote_version'] ?: 'Unknown') . "\n";
            if ($storedVersionData['remote_version']) {
                $this->compareVersions($currentVersion, $storedVersionData['remote_version']);
            }
            echo "Last checked: " . ($storedVersionData['last_checked'] ? date('Y-m-d H:i:s', $storedVersionData['last_checked']) : 'Unknown') . "\n";
            echo "Version check completed using cached data\n";
            return true;
        }
        echo "Config version differs from database or no cached data - fetching remote version\n";
        $latestVersion = $this->fetchLatestVersion();
        if (!$latestVersion) {
            echo "Failed to fetch latest version from all sources\n";
            return false;
        }
        echo "Latest version fetched: $latestVersion\n";
        $updateSuccess = $this->updateVersionDatabase($latestVersion, $currentVersion);
        echo "Version database update: " . ($updateSuccess ? 'SUCCESS' : 'FAILED') . "\n";
        if ($currentVersion && $latestVersion) {
            $this->compareVersions($currentVersion, $latestVersion);
        }
        return $updateSuccess;
    }
    private function getCurrentVersion() {
        if (!file_exists($this->configFile)) {
            echo "Config file not found: {$this->configFile}\n";
            return null;
        }
        $configData = json_decode(file_get_contents($this->configFile), true);
        if (!$configData || !isset($configData['version'])) {
            echo "Version not found in config.json\n";
            return null;
        }
        return $configData['version'];
    }
    private function fetchLatestVersion() {
        echo "Attempting to fetch from primary URL: {$this->primaryUrl}\n";
        $content = $this->fetchUrl($this->primaryUrl);
        if ($content === false) {
            echo "Primary URL unreachable, trying fallback URL: {$this->fallbackUrl}\n";
            $content = $this->fetchUrl($this->fallbackUrl);
            if ($content === false) {
                echo "Fallback URL also unreachable\n";
                return null;
            } else {
                echo "Successfully fetched from fallback URL\n";
            }
        } else {
            echo "Successfully fetched from primary URL\n";
        }
        return $this->parseVersionFromContent($content);
    }
    private function fetchUrl($url) {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_USERAGENT => '5q12-Indexer',
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
            CURLOPT_MAXREDIRS => 3
        ]);
        $content = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        if ($content === false) {
            echo "cURL error: $error\n";
            return false;
        }
        if ($httpCode !== 200) {
            echo "HTTP error: $httpCode\n";
            return false;
        }
        return $content;
    }
    private function parseVersionFromContent($content) {
        $lines = explode("\n", $content);
        if (empty($lines)) {
            echo "Empty content received\n";
            return null;
        }
        $firstLine = trim($lines[0]);
        echo "First line of repo file: $firstLine\n";
        if (preg_match('/^VERSION=(.+)$/', $firstLine, $matches)) {
            $version = trim($matches[1]);
            echo "Parsed version: $version\n";
            return $version;
        }
        echo "Could not parse version from first line\n";
        return null;
    }
    private function updateVersionDatabase($remoteVersion, $currentVersion) {
        if (!$this->versionPdo) {
            echo "Version database not available\n";
            return false;
        }
        try {
            $installationType = $this->determineInstallationType();
            $versionData = [
                'remote_version' => $remoteVersion,
                'current_version' => $currentVersion,
                'installation_type' => $installationType,
                'last_checked' => time()
            ];
            $stmt = $this->versionPdo->prepare("INSERT OR REPLACE INTO version_info (key, value, cached_at) VALUES (?, ?, ?)");
            $success = $stmt->execute([
                'remote_version_info',
                json_encode($versionData),
                time()
            ]);
            if ($success) {
                echo "Version data saved to database:\n";
                echo "  Remote version: $remoteVersion\n";
                echo "  Current version: " . ($currentVersion ?: 'Unknown') . "\n";
                echo "  Installation type: $installationType\n";
                echo "  Last checked: " . date('Y-m-d H:i:s') . "\n";
            }
            return $success;
        } catch (Exception $e) {
            echo "Error updating version database: " . $e->getMessage() . "\n";
            return false;
        }
    }
    private function determineInstallationType() {
        if (file_exists($this->indexerFilesDir . '/.docker')) {
            return 'docker';
        } elseif (file_exists($this->indexerFilesDir . '/.script')) {
            return 'script';
        } else {
            return 'manual';
        }
    }
}
try {
    $versionChecker = new VersionChecker($indexerFilesDir, $configFile);
    $success = $versionChecker->checkAndUpdateVersion();
    echo "\nVersion check completed " . ($success ? 'successfully' : 'with errors') . "\n";
    exit($success ? 0 : 1);
} catch (Exception $e) {
    echo "Fatal error: " . $e->getMessage() . "\n";
    exit(1);
}
?>