403Webshell
Server IP : 10.200.247.200  /  Your IP : 216.73.217.19
Web Server : Apache
System : Linux synergy-usa-sites 6.8.0-138-generic #138-Ubuntu SMP PREEMPT_DYNAMIC Fri Jul 31 22:41:49 UTC 2026 x86_64
User : jeremy ( 1001)
PHP Version : 8.4.25
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/development/callings.lvsaints.com/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/development/callings.lvsaints.com/releases.php
<?php
// ---------------------------------------------------------------------------
// Filesystem-based version control for uploaded sites.
//
// Each upload is a ZIP that we extract into its own folder under data/releases/.
// The "live" version is whichever folder the data/current symlink points at, so
// switching versions (or rolling back) is just re-pointing that one link.
//
//   data/
//     releases/
//       v1__20260703-153000/   <- extracted site (index.html lives here)
//       v2__20260703-160000/
//     current -> releases/v2__20260703-160000   (the active version)
//     meta/  v1__....json ...  (note / who / when, kept out of the served dir)
//     .htaccess                (deny direct web access; site.php serves instead)
//
// Nothing here touches the database — the folders *are* the version history.
// ---------------------------------------------------------------------------

declare(strict_types=1);

function data_dir(): string     { return __DIR__ . '/data'; }
function releases_dir(): string { return data_dir() . '/releases'; }
function meta_dir(): string     { return data_dir() . '/meta'; }
function current_link(): string { return data_dir() . '/current'; }

// Create the storage layout on first use and lock the folder to PHP-only access.
function ensure_dirs(): void
{
    foreach ([data_dir(), releases_dir(), meta_dir()] as $d) {
        if (!is_dir($d) && !@mkdir($d, 0775, true) && !is_dir($d)) {
            throw new RuntimeException("Cannot create storage folder: $d (check web-server write permissions).");
        }
    }
    $htaccess = data_dir() . '/.htaccess';
    if (!file_exists($htaccess)) {
        @file_put_contents($htaccess,
            "# Uploaded sites are served through site.php (after login), never directly.\n" .
            "<IfModule mod_authz_core.c>\n  Require all denied\n</IfModule>\n" .
            "<IfModule !mod_authz_core.c>\n  Order allow,deny\n  Deny from all\n</IfModule>\n"
        );
    }
}

// Name for the next release: sequential number + timestamp, e.g. v3__20260703-160000.
function next_version_name(): string
{
    $max = 0;
    foreach (glob(releases_dir() . '/v*__*', GLOB_ONLYDIR) ?: [] as $d) {
        if (preg_match('#/v(\d+)__#', $d, $m)) {
            $max = max($max, (int) $m[1]);
        }
    }
    return sprintf('v%d__%s', $max + 1, date('Ymd-His'));
}

// The folder name the "current" symlink points at, or null if nothing is live.
function active_version(): ?string
{
    $link = current_link();
    if (is_link($link)) {
        $t = readlink($link);
        return $t === false ? null : basename($t);
    }
    return null;
}

// Absolute path of the live release's document root, or null.
function active_dir(): ?string
{
    $name = active_version();
    if ($name === null) {
        return null;
    }
    $dir = releases_dir() . '/' . $name;
    return is_dir($dir) ? $dir : null;
}

function meta_path(string $name): string
{
    return meta_dir() . '/' . $name . '.json';
}

function write_meta(string $name, array $data): void
{
    ensure_dirs();
    @file_put_contents(meta_path($name), json_encode($data, JSON_PRETTY_PRINT));
}

function read_meta(string $name): array
{
    $f = meta_path($name);
    if (is_file($f)) {
        $d = json_decode((string) file_get_contents($f), true);
        if (is_array($d)) {
            return $d;
        }
    }
    return [];
}

// All versions, newest first, with their metadata and live flag.
function list_versions(): array
{
    $active = active_version();
    $out = [];
    foreach (glob(releases_dir() . '/*', GLOB_ONLYDIR) ?: [] as $d) {
        $name = basename($d);
        $meta = read_meta($name);
        $out[] = [
            'name'        => $name,
            'note'        => $meta['note'] ?? '',
            'uploaded_by' => $meta['uploaded_by'] ?? '',
            'uploaded_at' => $meta['uploaded_at'] ?? date('Y-m-d H:i:s', (int) filemtime($d)),
            'orig'        => $meta['orig'] ?? '',
            'is_live'     => ($name === $active),
            'has_index'   => is_file($d . '/index.html'),
        ];
    }
    usort($out, fn($a, $b) => strcmp($b['uploaded_at'], $a['uploaded_at']));
    return $out;
}

// Point "current" at $name. Uses a temp link + atomic rename so a viewer never
// sees a half-updated symlink.
function set_active(string $name): void
{
    ensure_dirs();
    if (!is_dir(releases_dir() . '/' . $name)) {
        throw new RuntimeException("Version “$name” does not exist.");
    }
    $tmp = data_dir() . '/.current-' . uniqid('', true);
    // Relative target so the link stays valid if the project is moved.
    if (!@symlink('releases/' . $name, $tmp)) {
        @unlink($tmp);
        throw new RuntimeException('Could not create the symlink. Does the server allow symlinks and have write access to the data/ folder?');
    }
    if (!@rename($tmp, current_link())) {
        @unlink($tmp);
        throw new RuntimeException('Could not update the “current” link.');
    }
}

// Extract an uploaded zip into a new release folder. Guards against zip-slip,
// strips a single wrapping folder, and requires an index.html to exist.
// Uses PHP's zip extension when available, else the `unzip` binary.
function extract_zip(string $tmpFile, string $name): void
{
    ensure_dirs();
    $target = releases_dir() . '/' . $name;
    if (!@mkdir($target, 0775, true) && !is_dir($target)) {
        throw new RuntimeException('Could not create the version folder.');
    }

    try {
        $entries = zip_list_entries($tmpFile);
        // Reject anything that would escape the target folder before writing a byte.
        foreach ($entries as $entry) {
            $n = str_replace('\\', '/', $entry);
            if (str_starts_with($n, '/') || preg_match('#(^|/)\.\.(/|$)#', $n)) {
                throw new RuntimeException('The zip contains an unsafe path and was rejected.');
            }
        }
        zip_extract_to($tmpFile, $target);
    } catch (Throwable $e) {
        rrmdir($target);
        throw $e;
    }

    // Junk that macOS adds when zipping from Finder.
    rrmdir($target . '/__MACOSX');
    @unlink($target . '/.DS_Store');

    // Symlinks could point outside the folder once served — never keep them.
    if (has_symlink($target)) {
        rrmdir($target);
        throw new RuntimeException('The zip contains a symbolic link and was rejected.');
    }

    flatten_single_wrapper($target);

    if (!is_file($target . '/index.html')) {
        rrmdir($target);
        throw new RuntimeException('No index.html was found in the zip (it must be at the top level, or inside a single folder).');
    }
}

// Locate the `unzip` binary, or null if it isn't installed.
function unzip_bin(): ?string
{
    foreach (['/usr/bin/unzip', '/bin/unzip', '/usr/local/bin/unzip'] as $p) {
        if (is_executable($p)) {
            return $p;
        }
    }
    return null;
}

// List the entry names in a zip, using whichever backend is available.
function zip_list_entries(string $file): array
{
    if (class_exists('ZipArchive')) {
        $zip = new ZipArchive();
        if ($zip->open($file) !== true) {
            throw new RuntimeException('That file is not a valid .zip archive.');
        }
        $names = [];
        for ($i = 0; $i < $zip->numFiles; $i++) {
            $n = $zip->getNameIndex($i);
            if ($n !== false) {
                $names[] = $n;
            }
        }
        $zip->close();
        return $names;
    }
    if ($bin = unzip_bin()) {
        $out = [];
        $code = 0;
        exec(escapeshellarg($bin) . ' -Z1 -- ' . escapeshellarg($file) . ' 2>/dev/null', $out, $code);
        if ($code !== 0) {
            throw new RuntimeException('That file is not a valid .zip archive.');
        }
        return array_map('rtrim', $out);
    }
    throw new RuntimeException('The server cannot read zip files. Enable the PHP “zip” extension (php-zip) or install the “unzip” program.');
}

// Extract a zip into $target using whichever backend is available.
function zip_extract_to(string $file, string $target): void
{
    if (class_exists('ZipArchive')) {
        $zip = new ZipArchive();
        if ($zip->open($file) !== true || !$zip->extractTo($target)) {
            throw new RuntimeException('Could not extract the zip.');
        }
        $zip->close();
        return;
    }
    if ($bin = unzip_bin()) {
        $code = 0;
        $out = [];
        exec(escapeshellarg($bin) . ' -o -qq -- ' . escapeshellarg($file)
             . ' -d ' . escapeshellarg($target) . ' 2>/dev/null', $out, $code);
        if ($code !== 0 && $code !== 1) { // 1 = warnings only (e.g. skipped junk)
            throw new RuntimeException('Could not extract the zip.');
        }
        return;
    }
    throw new RuntimeException('The server cannot read zip files. Enable the PHP “zip” extension (php-zip) or install the “unzip” program.');
}

// True if any symlink exists anywhere under $dir.
function has_symlink(string $dir): bool
{
    foreach (scandir($dir) ?: [] as $item) {
        if ($item === '.' || $item === '..') {
            continue;
        }
        $path = $dir . '/' . $item;
        if (is_link($path)) {
            return true;
        }
        if (is_dir($path) && has_symlink($path)) {
            return true;
        }
    }
    return false;
}

// If everything sits inside one wrapping folder (common when you zip a folder
// rather than its contents), lift that folder's contents up to the root.
function flatten_single_wrapper(string $target): void
{
    if (is_file($target . '/index.html')) {
        return;
    }
    $entries = array_values(array_filter(
        scandir($target) ?: [],
        fn($e) => $e !== '.' && $e !== '..' && $e !== '__MACOSX'
    ));
    if (count($entries) !== 1) {
        return;
    }
    $inner = $target . '/' . $entries[0];
    if (!is_dir($inner)) {
        return;
    }
    foreach (scandir($inner) ?: [] as $child) {
        if ($child === '.' || $child === '..') {
            continue;
        }
        @rename($inner . '/' . $child, $target . '/' . $child);
    }
    @rmdir($inner);
}

// Delete a version's folder + metadata. Refuses to delete the live one.
function delete_version(string $name): void
{
    if ($name === active_version()) {
        throw new RuntimeException('That version is live — make another version live before deleting it.');
    }
    $dir  = releases_dir() . '/' . $name;
    $real = realpath($dir);
    $base = realpath(releases_dir());
    if ($real === false || $base === false || !str_starts_with($real, $base . DIRECTORY_SEPARATOR)) {
        throw new RuntimeException('Invalid version.');
    }
    rrmdir($real);
    @unlink(meta_path($name));
}

// Recursively remove a directory (no-op if it doesn't exist).
function rrmdir(string $dir): void
{
    if (!is_dir($dir)) {
        return;
    }
    foreach (scandir($dir) ?: [] as $item) {
        if ($item === '.' || $item === '..') {
            continue;
        }
        $path = $dir . '/' . $item;
        is_dir($path) && !is_link($path) ? rrmdir($path) : @unlink($path);
    }
    @rmdir($dir);
}

Youez - 2016 - github.com/yon3zu
LinuXploit