[ Avaa Bypassed ]




Upload:

Command:

hmhc3928@18.118.186.185: ~ $
<?php
/**
 * UpdaterPlugin for phplist.
 *
 * This file is a part of UpdaterPlugin.
 *
 * This plugin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This plugin is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * @category  phplist
 *
 * @author    Duncan Cameron
 * @copyright 2023 Duncan Cameron
 * @license   http://www.gnu.org/licenses/gpl.html GNU General Public License, Version 3
 */

namespace phpList\plugin\UpdaterPlugin;

use Exception;
use FilesystemIterator;
use PharData;
use phpList\plugin\Common\Logger;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use Symfony\Component\Filesystem\Filesystem;
use ZipArchive;

class MD5Exception extends Exception
{
}

class ZipExtractor
{
    public function extract($file, $dir)
    {
        $zip = new ZipArchive();

        if (true !== ($error = $zip->open($file))) {
            throw new Exception(s('Unable to open zip file, %s', $error));
        }

        if (!$zip->extractTo($dir)) {
            throw new Exception(s('Unable to extract zip file %s to %s', $file, $dir));
        }
        $zip->close();
    }
}

class TgzExtractor
{
    public function extract($file, $dir)
    {
        $phar = new PharData($file);
        $phar->extractTo($dir);
    }
}

class Updater
{
    private $archiveFile;
    private $archiveUrl;
    private $basename;
    private $distributionDir;
    private $distributionArchive;
    private $extractor;
    private $logger;
    private $md5Url;
    private $timeout;
    private $workDir;

    public function __construct($version)
    {
        global $updaterConfig;

        $this->basename = sprintf('phplist-%s', $version);
        $archiveExtension = $updaterConfig['archive_extension'] ?? 'zip';
        $this->extractor = $archiveExtension == 'tgz' ? new TgzExtractor() : new ZipExtractor();
        $this->archiveFile = sprintf('%s.%s', $this->basename, $archiveExtension);
        $urlTemplate = false === strpos($version, 'RC')
            ? 'https://sourceforge.net/projects/phplist/files/phplist/%s/%s/download'
            : 'https://sourceforge.net/projects/phplist/files/phplist-development/%s/%s/download';
        $this->archiveUrl = sprintf($urlTemplate, $version, $this->archiveFile);
        $this->md5Url = sprintf($urlTemplate, $version, $this->basename . '.md5');
        $this->workDir = $updaterConfig['work'];
        $this->distributionDir = "$this->workDir/dist";
        $this->distributionArchive = "$this->workDir/$this->archiveFile";
        $this->logger = Logger::instance();
        $this->timeout = $updaterConfig['timeout'] ?? 60;

        if (isset($updaterConfig['memory_limit'])) {
            $memoryLimit = $updaterConfig['memory_limit'];
            $oldValue = ini_set('memory_limit', $memoryLimit);

            if ($oldValue === false) {
                $this->logger->debug('Unable to change memory_limit');
            } else {
                $this->logger->debug("Changed memory_limit from $oldValue to $memoryLimit");
            }
        }

        if (isset($updaterConfig['max_execution_time'])) {
            $maxExecutionTime = $updaterConfig['max_execution_time'];
            $oldValue = ini_set('max_execution_time', $maxExecutionTime);

            if ($oldValue === false) {
                $this->logger->debug('Unable to change max_execution_time');
            } else {
                $this->logger->debug("Changed max_execution_time from $oldValue to $maxExecutionTime");
            }
        }
    }

    public function downloadZipFile()
    {
        $this->logger->debug("Fetching MD5 file $this->md5Url");
        $md5Contents = fetchUrlDirect($this->md5Url);

        if ($md5Contents != '') {
            $filesMd5 = $this->parseMd5Contents($md5Contents);
            $expectedMd5 = $filesMd5[$this->archiveFile];

            // Use existing file if the MD5 is correct
            if (file_exists($this->distributionArchive)) {
                $actualMd5 = md5_file($this->distributionArchive);
                $this->logger->debug(sprintf('Expected md5 %s actual md5 %s', $expectedMd5, $actualMd5));

                if ($actualMd5 == $expectedMd5) {
                    $this->logger->debug(sprintf('Using existing archive file %s', $this->distributionArchive));

                    return;
                }
            }
        }
        $this->logger->debug(sprintf('Downloading %s', $this->archiveUrl));
        $archiveContents = fetchUrlDirect($this->archiveUrl, ['timeout' => $this->timeout]);

        if (!$archiveContents) {
            throw new Exception(s('Download of %s failed', $this->archiveUrl));
        }
        $r = file_put_contents($this->distributionArchive, $archiveContents);

        if (!$r) {
            throw new Exception(s('Unable to save archive file %s', $this->distributionArchive));
        }
        $this->logger->debug('Stored download');

        if ($md5Contents == '') {
            throw new MD5Exception(s('Unable to verify MD5, file "%s" does not exist', $this->md5Url));
        }
        $actualMd5 = md5($archiveContents);
        $this->logger->debug(sprintf('Expected md5 %s actual md5 %s', $expectedMd5, $actualMd5));

        if ($actualMd5 != $expectedMd5) {
            throw new MD5Exception(s('MD5 verification failed, expected %s actual %s', $expectedMd5, $actualMd5));
        }
        $this->logger->debug(sprintf('peak memory usage %s %s', formatBytes(memory_get_peak_usage()), formatBytes(memory_get_peak_usage(true))));
    }

    public function extractZipFile()
    {
        $fs = new Filesystem();

        if (file_exists($this->distributionDir)) {
            $fs->remove($this->distributionDir);
        }
        $this->logger->debug('Extracting archive');
        $this->extractor->extract($this->distributionArchive, $this->distributionDir);
        $this->logger->debug('Archive extracted');
        $this->logger->debug(sprintf('peak memory usage %s %s', formatBytes(memory_get_peak_usage()), formatBytes(memory_get_peak_usage(true))));
    }

    public function replaceFiles($listsDir)
    {
        global $updaterConfig, $configfile;

        $backupDir = sprintf('%s/phplist_backup_%s_%s', $this->workDir, VERSION, date('YmdHis'));

        // find the "lists" directory within the distribution
        $exists = false;
        $it = new RecursiveDirectoryIterator(
            $this->distributionDir,
            FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS
        );

        foreach (new RecursiveIteratorIterator($it, RecursiveIteratorIterator::SELF_FIRST) as $path => $fileinfo) {
            if ($fileinfo->isDir() && $fileinfo->getFileName() == 'lists') {
                $distListsDir = $path;
                $this->logger->debug("Using $distListsDir as lists directory");
                $exists = true;
                break;
            }
        }

        if (!$exists) {
            throw new Exception('Unable to find top level directory of distribution file');
        }

        // create set of specific files and directories to be copied from the backup
        $additionalFiles = [];

        if (realpath($configfile) == realpath("$listsDir/config/config.php")) {
            // config file is in the default location, restore config.php and any additional files
            $additionalFiles[] = 'config/config.php';
            $additional = array_diff(scandir("$listsDir/config"), scandir("$distListsDir/config"));

            foreach ($additional as $file) {
                $additionalFiles[] = "config/$file";
            }
        }

        if (PLUGIN_ROOTDIR == 'plugins' || realpath(PLUGIN_ROOTDIR) == realpath('plugins')) {
            // plugins are in the default location, restore additional files and directories
            $distPlugins = scandir("$distListsDir/admin/plugins");
            $installedPlugins = scandir("$listsDir/admin/plugins");
            $additional = array_diff($installedPlugins, $distPlugins);

            foreach ($additional as $file) {
                $additionalFiles[] = "admin/plugins/$file";
            }
        }

        if (isset($updaterConfig['files'])) {
            $additionalFiles = array_merge($additionalFiles, $updaterConfig['files']);
        }

        $fs = new Filesystem();
        $fs->mkdir($backupDir, 0755);

        // backup and move the files and directories in the distribution /lists directory
        $doNotInstall = $updaterConfig['do_not_install'] ?? [];

        foreach (scandir($distListsDir) as $file) {
            if ($file == '.' || $file == '..') {
                continue;
            }
            $sourceName = $distListsDir . '/' . $file;
            $targetName = $listsDir . '/' . $file;
            $backupName = $backupDir . '/' . $file;

            if (file_exists($targetName)) {
                $fs->rename($targetName, $backupName);
                $this->logger->debug("Renamed $targetName");
            }

            if (in_array($file, $doNotInstall)) {
                $this->logger->debug("Not installing $targetName");
            } else {
                $fs->rename($sourceName, $targetName);
                $this->logger->debug("Installed $targetName");
            }
        }

        // remove files and directories not be installed
        foreach ($doNotInstall as $relativePath) {
            $file = "$listsDir/$relativePath";

            if (file_exists($file)) {
                $fs->remove($file);
                $this->logger->debug("Removed $relativePath");
            }
        }

        // restore additional files and directories from the backup
        foreach ($additionalFiles as $relativePath) {
            $sourceName = "$backupDir/$relativePath";
            $targetName = "$listsDir/$relativePath";

            if (file_exists($sourceName)) {
                if (is_dir($sourceName)) {
                    $fs->mkdir($targetName, 0755);
                    $fs->mirror($sourceName, $targetName, null, ['override' => true]);
                } else {
                    $fs->copy($sourceName, $targetName, true);
                }
                $this->logger->debug("Restored $relativePath");
            }
        }

        // tidy-up
        $fs->remove($this->distributionDir);
        $this->logger->debug('Deleted distribution directory');

        if ($updaterConfig['delete_archive'] ?? true) {
            $fs->remove($this->distributionArchive);
            $this->logger->debug('Deleted distribution archive');
        }
        // purge old backups
        if (isset($updaterConfig['keep_backups'])
            && is_int($updaterConfig['keep_backups'])
            && $updaterConfig['keep_backups'] > 0) {
            $keep = $updaterConfig['keep_backups'];
            $backups = array_filter(
                scandir($this->workDir),
                function ($file) {
                    return preg_match('/^phplist_backup_.+\d{14}$/', $file);
                }
            );
            rsort($backups);
            $this->logger->debug(print_r($backups, true));

            if (count($backups) > $keep) {
                foreach (array_slice($backups, $keep) as $backup) {
                    $backupPath = "$this->workDir/$backup";
                    $fs->remove($backupPath);
                    $this->logger->debug("Deleted backup $backupPath");
                }
            } else {
                $this->logger->debug('No backups to delete');
            }
        }
        $this->logger->debug(sprintf('peak memory usage %s %s', formatBytes(memory_get_peak_usage()), formatBytes(memory_get_peak_usage(true))));
    }

    private function parseMd5Contents($md5Contents)
    {
        $md5 = [];

        foreach (explode("\n", trim($md5Contents)) as $line) {
            list($hash, $file) = preg_split('/\s+/', $line);
            $md5[$file] = $hash;
        }
        $this->logger->debug(print_r($md5, true));

        return $md5;
    }
}

Filemanager

Name Type Size Permission Actions
lan Folder 0755
vendor Folder 0755
Updater.php File 12.07 KB 0644
class_map.php File 427 B 0644
update.php File 5.16 KB 0644
version.txt File 14 B 0644