CasperSecurity

Current Path : /var/www/hrms.uiet.co.in/vendor/psy/psysh/src/ManualUpdater/
Upload File :
Current File : /var/www/hrms.uiet.co.in/vendor/psy/psysh/src/ManualUpdater/ManualUpdate.php

<?php

/*
 * This file is part of Psy Shell.
 *
 * (c) 2012-2025 Justin Hileman
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Psy\ManualUpdater;

use Psy\ConfigPaths;
use Psy\Configuration;
use Psy\Exception\ErrorException;
use Psy\Exception\InvalidManualException;
use Psy\VersionUpdater\Downloader;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;

/**
 * Manual update command.
 *
 * If a new manual version is available, this command will download and install it.
 */
class ManualUpdate
{
    const SUCCESS = 0;
    const FAILURE = 1;

    /** @var array{checker: Checker, installer: Installer}[] */
    private array $updates;
    private ?Downloader $downloader = null;

    /**
     * @param array{checker: Checker, installer: Installer} ...$updates Update configuration(s)
     */
    public function __construct(array ...$updates)
    {
        $this->updates = $updates;
    }

    /**
     * Create a ManualUpdate instance from Configuration and command-line input.
     *
     * @param Configuration   $config Configuration instance
     * @param InputInterface  $input  Input interface
     * @param OutputInterface $output Output interface
     *
     * @return self
     */
    public static function fromConfig(Configuration $config, InputInterface $input, OutputInterface $output): self
    {
        $lang = $input->getOption('update-manual') ?: null;

        // Clear the manual update cache when explicitly running --update-manual
        $cacheFile = $config->getManualUpdateCheckCacheFile();
        if ($cacheFile && \file_exists($cacheFile)) {
            @\unlink($cacheFile);
        }

        // Get current manual language before potentially deleting files
        $currentLang = null;
        $removedInvalidSqlite = false;
        $manualFile = $config->getManualDbFile();
        if ($manualFile && \file_exists($manualFile)) {
            try {
                $manual = $config->getManual();
                if ($manual) {
                    $currentMeta = $manual->getMeta();
                    $currentLang = $currentMeta['lang'] ?? null;
                }
            } catch (InvalidManualException $e) {
                $removedInvalidSqlite = \substr($e->getManualFile(), -7) === '.sqlite';
                self::handleInvalidManual($e, $input, $output);
            }
        }

        $dataDir = $config->getManualInstallDir();
        if ($dataDir === false) {
            throw new \RuntimeException('Unable to find a writable data directory for manual installation');
        }

        $phpManualPath = $dataDir.'/php_manual.php';
        $sqliteManualPath = $dataDir.'/php_manual.sqlite';

        $formats = self::getFormatsToUpdate(
            $input,
            $output,
            \file_exists($phpManualPath),
            \file_exists($sqliteManualPath),
            $removedInvalidSqlite,
            $sqliteManualPath
        );

        // Build update configurations for selected formats
        $checkerLang = $lang ?: $currentLang ?: 'en';
        $updates = [];

        foreach ($formats as $format) {
            $path = $format === 'php' ? $phpManualPath : $sqliteManualPath;
            $meta = self::getManualMeta($path);

            $updates[] = [
                'checker'   => new GitHubChecker($checkerLang, $format, $meta['version'] ?? null, $meta['lang'] ?? null),
                'installer' => new Installer($dataDir, $format),
            ];
        }

        return new self(...$updates);
    }

    /**
     * Allow the downloader to be injected for testing.
     *
     * @return void
     */
    public function setDownloader(Downloader $downloader)
    {
        $this->downloader = $downloader;
    }

    /**
     * Get the currently set Downloader or create one based on the capabilities of the php environment.
     *
     * @throws ErrorException if a downloader cannot be created for the php environment
     */
    private function getDownloader(): Downloader
    {
        if (!isset($this->downloader)) {
            return Downloader\Factory::getDownloader();
        }

        return $this->downloader;
    }

    /**
     * Update the manual installation.
     */
    public function run(InputInterface $input, OutputInterface $output): int
    {
        foreach ($this->updates as $update) {
            if (!$update['installer']->isDataDirWritable()) {
                $output->writeln('<error>Data directory is not writable.</error>');

                return self::FAILURE;
            }
        }

        $downloader = $this->getDownloader();
        $downloader->setTempDir(\sys_get_temp_dir());
        $installed = [];

        // Download and install each format
        foreach ($this->updates as $update) {
            $checker = $update['checker'];
            $installer = $update['installer'];

            if ($checker->isLatest()) {
                continue;
            }

            $latestVersion = $checker->getLatest();
            $downloadUrl = $checker->getDownloadUrl();

            $output->write("Downloading manual v{$latestVersion}...");

            try {
                $downloaded = $downloader->download($downloadUrl);
            } catch (ErrorException $e) {
                $output->write(' <error>Failed.</error>');
                $output->writeln(\sprintf('<error>%s</error>', $e->getMessage()));
                $downloader->cleanup();

                return self::FAILURE;
            }

            if (!$downloaded) {
                $output->writeln(' <error>Download failed.</error>');
                $downloader->cleanup();

                return self::FAILURE;
            }

            $output->write(' <info>OK</info>'.\PHP_EOL);

            $downloadedFile = $downloader->getFilename();

            if (!$installer->install($downloadedFile)) {
                $downloader->cleanup();
                $output->writeln('<error>Failed to install manual.</error>');

                return self::FAILURE;
            }

            $installed[] = [$installer->getInstallPath(), $latestVersion];

            $downloader->cleanup();
        }

        if (empty($installed)) {
            $output->writeln('<info>Manual is up-to-date.</info>');
        } else {
            foreach ($installed as [$installPath, $version]) {
                $prettyPath = ConfigPaths::prettyPath($installPath);
                $output->writeln("Installed manual v{$version} to <info>{$prettyPath}</info>");
            }
        }

        return self::SUCCESS;
    }

    /**
     * Handle an invalid manual file by prompting the user to remove it.
     *
     * @param InvalidManualException $e      The exception containing invalid manual details
     * @param InputInterface         $input  Input interface
     * @param OutputInterface        $output Output interface
     *
     * @throws \RuntimeException if user declines to remove the file or removal fails
     */
    private static function handleInvalidManual(InvalidManualException $e, InputInterface $input, OutputInterface $output): void
    {
        $prettyPath = ConfigPaths::prettyPath($e->getManualFile());
        $output->writeln(\sprintf('<error>Invalid manual file detected:</error> <info>%s</info>', $prettyPath));
        $output->writeln('');

        $helper = new QuestionHelper();
        $question = new ConfirmationQuestion('Remove this file and continue? [Y/n] ', true);

        if (!$helper->ask($input, $output, $question)) {
            throw new \RuntimeException('Manual update cancelled.');
        }

        if (!\unlink($e->getManualFile())) {
            throw new \RuntimeException(\sprintf('Failed to remove file: %s', $prettyPath));
        }

        $output->writeln('<info>Invalid manual file removed.</info>');
        $output->writeln('');
    }

    /**
     * Prompt user to download PHP format manual when they have/had legacy SQLite.
     *
     * @param InputInterface  $input      Input interface
     * @param OutputInterface $output     Output interface
     * @param string          $manualFile Path to current/former SQLite manual file
     * @param bool            $wasRemoved Whether the file was already removed
     *
     * @return bool True if user wants to download PHP format
     */
    private static function promptMigrateToV3(InputInterface $input, OutputInterface $output, string $manualFile, bool $wasRemoved): bool
    {
        $prettyPath = ConfigPaths::prettyPath($manualFile);
        $verb = $wasRemoved ? 'had' : 'have';
        $output->writeln(\sprintf('You %s a legacy SQLite manual: <info>%s</info>', $verb, $prettyPath));
        $output->writeln('');

        $helper = new QuestionHelper();
        $question = new ConfirmationQuestion('Download the current manual format? [Y/n] ', true);

        return $helper->ask($input, $output, $question);
    }

    /**
     * Determine which manual formats should be updated.
     *
     * @param InputInterface  $input                Input interface
     * @param OutputInterface $output               Output interface
     * @param bool            $hasPhpManual         Whether PHP manual exists
     * @param bool            $hasSqliteManual      Whether SQLite manual exists
     * @param bool            $removedInvalidSqlite Whether we just removed an invalid SQLite manual
     * @param string          $sqliteManualPath     Path to SQLite manual file
     *
     * @return string[] Array of format names to update ('php', 'sqlite')
     */
    private static function getFormatsToUpdate(
        InputInterface $input,
        OutputInterface $output,
        bool $hasPhpManual,
        bool $hasSqliteManual,
        bool $removedInvalidSqlite,
        string $sqliteManualPath
    ): array {
        // Only SQLite exists (or just removed invalid SQLite): offer to add PHP format
        if (!$hasPhpManual && ($hasSqliteManual || $removedInvalidSqlite)) {
            if (self::promptMigrateToV3($input, $output, $sqliteManualPath, $removedInvalidSqlite)) {
                return ['php', 'sqlite'];
            }

            return ['sqlite'];
        }

        // PHP exists, or neither exist: default to PHP, and include SQLite if it exists
        $formats = ['php'];
        if ($hasSqliteManual) {
            $formats[] = 'sqlite';
        }

        return $formats;
    }

    /**
     * Get manual metadata from a file.
     *
     * @param string $path Path to manual file
     *
     * @return array|null Metadata array with 'version' and 'lang' keys, or null if unavailable
     */
    private static function getManualMeta(string $path): ?array
    {
        if (!\file_exists($path)) {
            return null;
        }

        try {
            if (\substr($path, -4) === '.php') {
                $manual = new \Psy\Manual\V3Manual($path);

                return $manual->getMeta();
            }

            if (\substr($path, -7) === '.sqlite') {
                $pdo = new \PDO('sqlite:'.$path);
                $manual = new \Psy\Manual\V2Manual($pdo);

                return $manual->getMeta();
            }
        } catch (\Exception $e) {
            // Ignore errors reading manual metadata
        }

        return null;
    }
}
Hacker Blog, Shell İndir, Sql İnjection, XSS Attacks, LFI Attacks, Social Hacking, Exploit Bot, Proxy Tools, Web Shell, PHP Shell, Alfa Shell İndir, Hacking Training Set, DDoS Script, Denial Of Service, Botnet, RFI Attacks, Encryption
Telegram @BIBIL_0DAY