HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/iphim.naniguide.com/public/install_files/php/Installer.php
<?php

use App\Models\User;
use Common\Admin\Appearance\GenerateFavicon;
use Common\Auth\Permissions\Permission;
use Common\Database\MigrateAndSeed;
use Common\Settings\DotEnvEditor;
use Illuminate\Encryption\Encrypter;
use Illuminate\Foundation\Application;

class Installer
{
    /**
     * @var string
     */
    protected $baseDirectory;

    /**
     * @var string
     */
    private $logFile;

    public function __construct()
    {
        $this->baseDirectory = PATH_INSTALL;
        $this->logFile = PATH_INSTALL . '/public/install_files/install.log';
        $this->logPost();

        if (!is_null($handler = $this->post('handler'))) {
            if (!strlen($handler)) {
                exit();
            }

            try {
                if (!preg_match('/^on[A-Z]{1}[\w+]*$/', $handler)) {
                    throw new Exception(
                        sprintf('Invalid handler: %s', $this->e($handler)),
                    );
                }

                if (
                    method_exists($this, $handler) &&
                    ($result = $this->$handler()) !== null
                ) {
                    $this->log(
                        'Execute handler (%s): %s',
                        $handler,
                        print_r($result, true),
                    );
                    header('Content-Type: application/json');
                    die(json_encode($result));
                }
            } catch (Exception $ex) {
                header(
                    $_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error',
                    true,
                    500,
                );
                $this->log(
                    'Handler error (%s): %s',
                    $handler,
                    $ex->getMessage(),
                );
                $this->log(['Trace log:', '%s'], $ex->getTraceAsString());
                die($ex->getMessage());
            }

            exit();
        }
    }

    protected function onCheckRequirements()
    {
        $this->log('Check requirements: start');

        $this->createHtaccessFiles();

        $result = [
            'PHP Version' => [
                'result' => version_compare(PHP_VERSION, MINIMUM_VERSION, '>'),
                'errorMessage' =>
                    'You need at least ' .
                    MINIMUM_VERSION .
                    ' PHP Version to install.',
            ],
            'PDO' => [
                'result' => defined('PDO::ATTR_DRIVER_NAME'),
                'errorMessage' => 'PHP PDO extension is required.',
            ],
            'XML' => [
                'result' => extension_loaded('xml'),
                'errorMessage' => 'PHP XML extension is required.',
            ],
            'Mbstring' => [
                'result' => extension_loaded('mbstring'),
                'errorMessage' => 'PHP mbstring extension is required.',
            ],
            'Fileinfo' => [
                'result' => extension_loaded('fileinfo'),
                'errorMessage' => 'PHP fileinfo extension is required.',
            ],
            'OpenSSL' => [
                'result' => extension_loaded('openssl'),
                'errorMessage' => 'PHP openssl extension is required.',
            ],
            'GD' => [
                'result' => extension_loaded('gd'),
                'errorMessage' => 'PHP GD extension is required.',
            ],
            'fpassthru' => [
                'result' => function_exists('fpassthru'),
                'errorMessage' =>
                    '"fpassthru" PHP function needs to be enabled.',
            ],
            'Curl' => [
                'result' => extension_loaded('curl'),
                'errorMessage' => 'PHP curl functionality needs to be enabled.',
            ],
            'Zip' => [
                'result' => class_exists('ZipArchive'),
                'errorMessage' =>
                    'PHP ZipArchive extension needs to be installed.',
            ],
        ];

        $allPass = array_filter($result, function ($item) {
            return !$item['result'];
        });

        $this->log('Check requirements: end', $allPass ? '+OK' : '=FAIL');

        return $result;
    }

    protected function onCheckFileSystem()
    {
        $this->log('Check filesystem: start');

        $directories = [
            '',
            'storage',
            'storage/app',
            'storage/logs',
            'storage/framework',
            'public/storage',
        ];

        $results = [];
        foreach ($directories as $directory) {
            $path = rtrim("{$this->baseDirectory}/$directory", '/');
            $writable = is_writable($path);
            $result = [
                'path' => $path,
                'result' => $writable,
                'errorMessage' => '',
            ];
            if (!$writable) {
                $result['errorMessage'] = is_dir($path)
                    ? 'Make this directory writable by giving it 0755 or 0777 permissions via file manager.'
                    : 'Make this directory writable by giving it 644 permissions via file manager.';
            }

            $results[] = $result;
        }

        $files = ['.htaccess', 'public/.htaccess'];

        if (
            !$this->fileExistsAndNotEmpty('.env') &&
            !$this->fileExistsAndNotEmpty('env.example')
        ) {
            $results[] = [
                'path' => $this->baseDirectory,
                'result' => false,
                'errorMessage' =>
                    'Make sure <strong>env.example</strong> or <strong>.env</strong> file has been uploaded properly to the directory above and is writable.',
            ];
        }

        foreach ($files as $file) {
            $results[] = [
                'path' => "{$this->baseDirectory}/$file",
                'result' => $this->fileExistsAndNotEmpty($file),
                'errorMessage' => "Make sure <strong>$file</strong> file has been uploaded properly to your server and is writable.",
            ];
        }

        $allPass = array_filter($results, function ($item) {
            return !$item['result'];
        });

        $this->log(
            'Check filesystem: end',
            $results,
            $allPass ? '+OK' : '=FAIL',
        );

        return $results;
    }

    /**
     * @param string $path
     * @return bool
     */
    protected function fileExistsAndNotEmpty($path)
    {
        $filePath = "{$this->baseDirectory}/$path";
        $writable = is_writable($filePath);
        $content = $writable ? trim(file_get_contents($filePath)) : '';
        return $writable && strlen($content);
    }

    protected function onValidateAndInsertDatabaseCredentials()
    {
        $config = [
            'db_host' => null,
            'db_database' => null,
            'db_port' => null,
            'db_username' => null,
            'db_password' => null,
            'db_prefix' => null,
        ];
        array_walk($config, function (&$value, $key) {
            $value = $value ?: $this->post($key);
        });

        $this->insertDBCredentials($config);
    }

    protected function onValidateAdminAccount()
    {
        if (!strlen($this->post('email'))) {
            throw new InstallerException(
                'Please specify administrator email address',
                'email',
            );
        }

        if (!filter_var($this->post('email'), FILTER_VALIDATE_EMAIL)) {
            throw new InstallerException(
                'Please specify valid email address',
                'email',
            );
        }

        if (!strlen($this->post('password'))) {
            throw new InstallerException('Please specify password', 'password');
        }

        if (strlen($this->post('password')) < 4) {
            throw new InstallerException(
                'Please specify password length more than 4 characters',
                'password',
            );
        }

        if (strlen($this->post('password')) > 255) {
            throw new InstallerException(
                'Please specify password length less than 64 characters',
                'password',
            );
        }

        if (!strlen($this->post('password_confirmation'))) {
            throw new InstallerException(
                'Please confirm chosen password',
                'password_confirmation',
            );
        }

        if (
            strcmp(
                $this->post('password'),
                $this->post('password_confirmation'),
            )
        ) {
            throw new InstallerException(
                'Specified password does not match the confirmed password',
                'password',
            );
        }
    }

    protected function onInstallApplication()
    {
        $this->bootFramework();

        // Fix "index is too long" issue on MariaDB and older mysql versions
        Schema::defaultStringLength(191);

        // Generate key
        $appKey =
            'base64:' .
            base64_encode(Encrypter::generateKey(config('app.cipher')));

        app(DotEnvEditor::class)->write([
            'app_key' => $appKey,
        ]);

        app(MigrateAndSeed::class)->execute(function () {
            $this->createAdminAccount();
        });

        $this->putAppInProductionEnv();

        // move default favicons
        File::copyDirectory(
            "$this->baseDirectory/assets/favicons",
            public_path(GenerateFavicon::FAVICON_DIR),
        );

        Cache::flush();

        try {
            $this->deleteInstallationFiles();
        } catch (Exception $e) {
            //
        }
    }

    public function createAdminAccount()
    {
        $email = $this->post('email');
        $user = app(User::class)->firstOrNew(['email' => $email]);
        $user->username = $this->post('username');
        $user->email = $email;
        $user->password = Hash::make($this->post('password'));
        $user->email_verified_at = now();
        $user->save();
        $adminPermission = app(Permission::class)->firstOrCreate(
            ['name' => 'admin'],
            [
                'name' => 'admin',
                'group' => 'admin',
                'display_name' => 'Super Admin',
                'description' => 'Give all permissions to user.',
            ],
        );
        $user->permissions()->attach($adminPermission->id);
        Auth::login($user);
    }

    /**
     * Insert user supplied db credentials into .env file.
     *
     * @param array $credentials
     * @return void
     */
    protected function insertDBCredentials($credentials)
    {
        $this->bootFramework();

        $envFile = $this->baseDirectory . '/.env';
        $envExampleFile = $this->baseDirectory . '/env.example';
        $envExists = file_exists($envFile);

        (new DotEnvEditor())->write($credentials, $this->envFileName());

        if (!$envExists) {
            // rename env.example to .env
            rename($envExampleFile, $envFile);
        }
    }

    private function putAppInProductionEnv()
    {
        $writer = app(DotEnvEditor::class);
        $writer->write([
            'app_url' => $this->getBaseUrl(),
            'app_env' => 'production',
            'app_debug' => false,
            'installed' => true,
        ]);
    }

    protected function createHtaccessFiles($force = false, $alternative = false)
    {
        $rootHtaccess = "{$this->baseDirectory}/.htaccess";
        $rootHtaccessStub = "{$this->baseDirectory}/htaccess.example";
        $publicHtaccess = "{$this->baseDirectory}/public/.htaccess";
        $publicHtaccessStub = "{$this->baseDirectory}/public/htaccess.example";
        $parts = parse_url($this->getBaseUrl());

        if (!file_exists($rootHtaccess) || $force) {
            $contents = file_get_contents($rootHtaccessStub);
            if ($alternative) {
                $path = isset($parts['path']) ? $parts['path'] : '/';
                $contents = str_replace(
                    '# RewriteBase /',
                    "RewriteBase $path",
                    $contents,
                );
            }
            file_put_contents($rootHtaccess, $contents);
        }

        if (!file_exists($publicHtaccess) || $force) {
            $contents = file_get_contents($publicHtaccessStub);
            if ($alternative) {
                $path = isset($parts['path']) ? $parts['path'] : '';
                $contents = str_replace(
                    'index.php',
                    "{$path}/index.php",
                    $contents,
                );
                $contents = str_replace(
                    '# RewriteBase /',
                    "RewriteBase $path",
                    $contents,
                );
            }
            file_put_contents($publicHtaccess, $contents);
        }
    }

    private function deleteInstallationFiles()
    {
        $dir = $this->baseDirectory . '/public/install_files';

        $it = new RecursiveDirectoryIterator(
            $dir,
            RecursiveDirectoryIterator::SKIP_DOTS,
        );
        $files = new RecursiveIteratorIterator(
            $it,
            RecursiveIteratorIterator::CHILD_FIRST,
        );

        foreach ($files as $file) {
            if ($file->isDir()) {
                rmdir($file->getRealPath());
            } else {
                unlink($file->getRealPath());
            }
        }

        @rmdir($dir);
    }

    public function startNewLogSection()
    {
        file_put_contents(
            $this->logFile,
            '"========================== INSTALLATION LOG SECTION ========================"' .
                PHP_EOL,
            FILE_APPEND,
        );
    }

    public function logPost()
    {
        if (!isset($_POST) || !count($_POST)) {
            return;
        }
        $postData = $_POST;

        if (array_key_exists('disableLog', $postData)) {
            $postData = ['disableLog' => true];
        }

        /*
         * Sensitive data fields
         */
        if (isset($postData['admin_email'])) {
            $postData['admin_email'] = '*******@*****.com';
        }
        $fieldsToErase = [
            'encryption_code',
            'admin_password',
            'admin_confirm_password',
            'db_pass',
            'project_id',
        ];
        foreach ($fieldsToErase as $field) {
            if (isset($postData[$field])) {
                $postData[$field] = '*******';
            }
        }

        file_put_contents(
            $this->logFile,
            '.============================ POST REQUEST ==========================.' .
                PHP_EOL,
            FILE_APPEND,
        );
        $this->log('Postback payload: %s', print_r($postData, true));
    }

    public function log()
    {
        $args = func_get_args();
        $message = array_shift($args);

        if (is_array($message)) {
            $message = implode(PHP_EOL, $message);
        }

        $message =
            '[' .
            date('Y/m/d h:i:s', time()) .
            '] ' .
            vsprintf($message, $args) .
            PHP_EOL;

        try {
            file_put_contents($this->logFile, $message, FILE_APPEND);
        } catch (Exception $e) {
            //
        }
    }

    protected function bootFramework()
    {
        $autoloadFile = $this->baseDirectory . '/vendor/autoload.php';
        if (!file_exists($autoloadFile)) {
            throw new Exception(
                'Unable to find autoloader: ~/vendor/autoload.php',
            );
        }
        require $autoloadFile;

        $appFile = $this->baseDirectory . '/bootstrap/app.php';
        if (!file_exists($appFile)) {
            throw new Exception(
                'Unable to find app loader: ~/bootstrap/app.php',
            );
        }
        /** @var Application $app */
        $app = require_once $appFile;
        $kernel = $app->make('Illuminate\Contracts\Console\Kernel');
        $kernel->bootstrap();
    }

    protected function post($var, $default = null)
    {
        if (array_key_exists($var, $_REQUEST)) {
            $result = $_REQUEST[$var];
            if (is_string($result)) {
                $result = trim($result);
            }
            return $result;
        }

        return $default;
    }

    public function getBaseUrl($suffix = null)
    {
        if (isset($_SERVER['HTTP_HOST'])) {
            $baseUrl =
                !empty($_SERVER['HTTPS']) &&
                strtolower($_SERVER['HTTPS']) !== 'off'
                    ? 'https'
                    : 'http';
            $baseUrl .= '://' . $_SERVER['HTTP_HOST'];
            $baseUrl .= str_replace(
                basename($_SERVER['SCRIPT_NAME']),
                '',
                $_SERVER['SCRIPT_NAME'],
            );
        } else {
            $baseUrl = 'http://localhost/';
        }

        $baseUrl = rtrim($baseUrl, '/');
        $baseUrl = preg_replace('/\/public$/', '', $baseUrl);
        $baseUrl = str_replace('install_files', '', $baseUrl);
        $baseUrl = trim($baseUrl);

        return rtrim($suffix ? "$baseUrl/$suffix" : $baseUrl, '/');
    }

    public function e($value)
    {
        return htmlentities($value, ENT_QUOTES, 'UTF-8', false);
    }

    private function envFileName()
    {
        return file_exists("$this->baseDirectory/.env")
            ? '.env'
            : 'env.example';
    }
}