shell bypass 403

Cubjrnet7 Shell


name : bfSnapshot.php
<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork 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.
 *
 * bfNetwork 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact [email protected]
 */

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Schema\ChangeSet;
use Joomla\CMS\Version;
use Joomla\Component\Installer\Administrator\Model\DatabaseModel;

require 'bfEncrypt.php';

/*
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.
 */

// require all we need to access Joomla API
if (! defined('BF_JOOMLA_INIT_DONE')) {
    require_once 'bfInitJoomla.php';
}
require_once 'bfActivitylog.php';

final class bfSnapshot
{
    public $_data;

    private $db;

    private $version;

    private $container;

    private $config;

    public function __construct()
    {
        $this->cleanOurCrap();
        // Ask Joomla to report config through its API

        $this->container = Factory::getContainer();
        $this->config    = $this->container->get('config');

        // Connect to the database
        $this->initDb();

        $this->logSnapshot();

        $session_save_path = ini_get('session.save_path');

        $this->_data = [
            'version'                    => $this->getJoomlaVersion(),
            'connectorversion'           => file_get_contents('./VERSION'),
            'php_version'                => \PHP_VERSION,
            'php_disabled_functions'     => ini_get('disable_functions'),
            'display_errors'             => ini_get('display_errors'),
            'register_globals'           => (int) ini_get('register_globals'),
            'safe_mode'                  => (int) ini_get('safe_mode'),
            'file_uploads'               => (int) ini_get('file_uploads'),
            'magic_quotes_gpc'           => (int) ini_get('magic_quotes_gpc'),
            'magic_quotes_runtime'       => (int) ini_get('magic_quotes_runtime'),
            'session_autostart'          => (int) ini_get('session_autostart'),
            'gc_probability'             => (int) ini_get('session.gc_probability'),
            'mysql_version'              => $this->initDb(),
            'session_save_path'          => @ini_get('session.save_path') ? ini_get('session.save_path') : '/tmp',
            'is_windows_host'            => (int) ('WIN' == substr(\PHP_OS, 0, 3)) ? 1 : 0,
            'session_save_path_writable' => (int) @is_writable($session_save_path),
            'db_prefix'                  => $this->config->get('dbprefix', ''),
            'dbs_visible'                => $this->getVisibleDbsCount(),
            'db_user_is_root'            => (int) ('root' == $this->config->get('user', '') ? 1 : 0),
            'db_bak_tables'              => (int) $this->hasBakTables(),
            'memory_limit'               => ini_get('memory_limit'),
            'has_installation_folders'   => (int) $this->hasInstallationFolders(),
            'site_debug_enabled'         => (int) $this->config->get('debug') ? 1 : 0,
            'has_ftp_configured'         => (int) $this->checkFTPLayer(),
            'numberofsuperadmins'        => $this->getNumberOfSuperAdmins(),
            'adminusernames'             => $this->getAdminUserNameCount(),
            'neverloggedinusers'         => $this->getNeverLoggedInUsersCount(),
            'hasjce'                     => $this->hasExtensionWithNameInstalled('com_jce'),
            'hasakeebabackup'            => $this->hasExtensionWithNameInstalled('com_akeebabackup'),
            'site_offline'               => $this->config->get('offline', ''),
            'cache_enabled'              => $this->config->get('caching', ''),
            'sef_enabled'                => $this->config->get('sef', ''),
            'tmplogfolderswritable'      => (int) $this->hastmplogfolderswritable(),
            'extensionupdatesavailable'  => null,
            // Now called in separate job was $this->hasUpdatesAvailable(),
            'defaulttemplateused'       => (int) $this->hasUsedDefaultTemplate(),
            'tpequalsone'               => $this->hastpequalsone(),
            'configsymlinked'           => (is_link(JPATH_BASE . '/configuration.php') ? 1 : 0),
            'kickstartseen'             => (int) $this->kickstartexists(),
            'fpaseen'                   => (int) $this->fpaexists(),
            'userregistrationenabled'   => (int) ComponentHelper::getParams('com_users')->get('allowUserRegistration'),
            'has_root_htaccess'         => (int) (file_exists(JPATH_BASE . '/.htaccess') ? 1 : 0),
            'adminhtaccess'             => (int) (file_exists(JPATH_BASE . '/administrator/.htaccess') ? 1 : 0),
            'gzipenabled'               => (int) $this->config->get('gzip', ''),
            'gcerrorreportingnone'      => (int) $this->getErrorReportingLevel(),
            'livesitevarset'            => strlen($this->config->get('live_site', '')) > 1 ? 1 : 0,
            'cookiedomainpath'          => ($this->config->get('cookie_path') || $this->config->get('cookie_domain')) ? 1 : 0,
            'sessionlifetime'           => (int) $this->config->get('lifetime'),
            'akeebabackupscount'        => (int) $this->getNumberOfAkeebaBackups(),
            'md5passwords'              => (int) $this->hasmd5passwords(),
            'tmplogfoldersdefaultpaths' => (int) $this->hastmplogfoldersdefaultpaths(),
            'max_allowed_packet'        => (int) $this->getMaxAllowedPacket(),
            'jceversion'                => $this->checkJCEVersion(),
            'fluff'                     => (int) $this->checkfluff(),
            'db_schema'                 => $this->checkdbschema(),
            'robots_blocks_media'       => (int) $this->checkRobotsBlocksMedia(),
            'server_hostname'           => function_exists('gethostname') ? gethostname() : php_uname('n'),
            'akeeba_dir_problems'       => 0,
            // @deprecated
            'diskspace'                 => $this->getDiskSpace(),
            'hacked'                    => $this->checkIf100percentHackedOrNot(),
            'new_usertype'              => $this->getNewUserType(),
            'non2faadmins'              => (int) $this->getNon2FaAdmins(),
            'users_hacked'              => $this->checkJoomlaUserHelperHack2016(),
            'sessiongcpublished'        => $this->getSessionGCStatus(),
            'twofactorenabled'          => $this->getTwoFactorPluginsEnabled(),
            'adminfilterfixed'          => $this->getAdminFilterFixed(),
            'userfilterfixed'           => $this->getUserFilterFixed(),
            'plaintextpasswordsfixed'   => $this->getPlaintextpasswordsFixed(),
            'uploadsettingsfixed'       => (int) $this->getUploadsettingsfixed(),
            'captchaenabled'            => (int) $this->getCaptchaDetails(),
            'useractionlogenabled'      => (int) $this->getUseractionlogenabled(),
            'plgprivacyconsentenabled'  => (int) $this->getPrivacyConsentPluginEnabled(),
            'useractionlogiplogenabled' => (int) $this->getActionLogsIPLoggingEnabled(),
            'systemlogrotationenabled'  => (int) $this->getSystemLogRotationEnabled(),
            'hasprivacypolicy'          => (int) $this->hasprivacypolicy(),
            'privacypendingremove'      => (int) $this->getPrivacypendingremove(),
            'privacycompletedexport'    => (int) $this->getPrivacycompletedexport(),
            'privacypendingexport'      => (int) $this->getPrivacypendingexport(),
            'privacycompletedremove'    => (int) $this->getPrivacycompletedremove(),
            'privacyoverdue'            => (int) $this->getPrivacyoverdue(),
            'privacyconfirmedremove'    => (int) $this->getPrivacyconfirmedremove(),
            'privacyconfirmedexport'    => (int) $this->getPrivacyconfirmedexport(),
            'enablepurge30days'         => (int) $this->getPurge30Days(),
            'extensionsjson'            => $this->getExtensions(),
            'hasrootuser'               => $this->config->get('root_user') ? 1 : 0,
            'debuglanguage'             => $this->config->get('debug_lang') ? 1 : 0,
            'apilogenabled'             => (int) ComponentHelper::getParams('com_actionlogs')->get('loggable_api'),
            'postinstallmsgcount'       => count($this->getPostInstallMessages()),
            'sendcopytosubmitter'       => (int) ComponentHelper::getParams('com_contact')->get('show_email_copy', 0),
            'fileinfo'                  => \extension_loaded('fileinfo'),
            'guidedtour'                => (int) $this->getGuidedToursEnabled(),
            'thumbnails'                => (int) $this->getThumbnailsEnabled(),
            'updatesource'              => (string) ComponentHelper::getParams('com_joomlaupdate')->get('updatesource'),
            'activetheme'               => (string) $this->getThemeName(),
            'updateemails'              => (int) $this->getUpdateEmailsState(),
            'logeverything'              => (int) $this->config->get('log_everything', '0'),
            'logdeprecated'              => (int) $this->config->get('log_deprecated', '0'),
        ];
    }

    public function getUpdateEmailsState()
    {
        $sql      = 'select count(*) from #__extensions where type = "plugin" and element = "updatenotification" and enabled = 1';
        $this->db->setQuery($sql);
        return $this->db->LoadResult();
    }

    public function getThemeName()
    {

        try {
            $sql = 'select template from #__template_styles where client_id = 0 and home = 1 LIMIT 1';
            $this->db->setQuery($sql);
            $row         = $this->db->LoadObject();
            $data        = [];
            $data['Name']=$row->template;
            return json_encode($data);
        } catch (\Exception $exception) {

        }

        return '';
    }

    public function getThumbnailsEnabled()
    {
        $this->db->setQuery("SELECT params FROM `#__extensions` WHERE `name` = 'plg_filesystem_local'");

        $params = $this->db->LoadResult();

        if ('{}' == $params || null == $params || '' == $params) {
            return;
        }

        $params = json_decode($params, JSON_OBJECT_AS_ARRAY);
        if (! array_key_exists('directories', $params)) {
            return;
        }

        $thumbsCount = 0;
        foreach ($params['directories'] as $directory) {
            if (! array_key_exists('thumbs', $directory)) {
                continue;
            }

            if ($directory['thumbs'] == 1) {
                $thumbsCount++;
            }
        }

        return (int) $thumbsCount === \count($params['directories']);
    }

    /**
     * Get the post install messages from a Joomla 3+ site.
     */
    public function getPostInstallMessages()
    {
        require JPATH_BASE . '/administrator/components/com_postinstall/src/Helper/PostinstallHelper.php';
        require JPATH_BASE . '/administrator/components/com_postinstall/src/Model/MessagesModel.php';

        $model = Factory::getApplication()
            ->bootComponent('com_postinstall')
            ->getMVCFactory()
            ->createModel('Messages', 'Administrator', [
                'ignore_request' => true,
            ]);

        $messages = $model->getItems();
        foreach ($messages as $k => $item) {
            $item->title_key       = Text::_($item->title_key);
            $item->description_key = Text::_($item->description_key);
        }

        return $messages;
    }

    private function logSnapshot()
    {
        bfActivitylog::getInstance()->log(
            'bfNetwork',
            '',
            'Snapshot Taken',
            'onSnapshotTaken',
            '',
            null,
            null,
            '',
            bfEvents::onSnapshotTaken,
            'onSnapshotTaken',
            bfEvents::onSnapshotTaken
        );
    }

    public function getExtensions()
    {
        require 'bfExtensions.php';
        $ext = new bfExtensions();

        return $ext->getExtensions();
    }

    /**
     * Get the number of days to delete logs after from the System - User Actions Log.
     *
     * @return int
     */
    public function getPurge30Days()
    {
        $this->db->setQuery("SELECT params FROM `#__extensions` WHERE `name` = 'PLG_SYSTEM_ACTIONLOGS'");

        $params = $this->db->LoadResult();

        if ('{}' == $params || $params === null) {
            return;
        }

        $params = json_decode($params);

        if (! $params) {
            return;
        }

        return $params->logDeletePeriod;
    }

    public function getPrivacypendingremove()
    {
        $this->db->setQuery("select count(*) from #__privacy_requests where status = 0 and request_type = 'remove'");

        return $this->db->LoadResult();
    }

    public function getPrivacyconfirmedremove()
    {
        $this->db->setQuery("select count(*) from #__privacy_requests where status = 1 and request_type = 'remove'");

        return $this->db->LoadResult();
    }

    public function getPrivacyconfirmedexport()
    {
        $this->db->setQuery("select count(*) from #__privacy_requests where status = 1 and request_type = 'export'");

        return $this->db->LoadResult();
    }

    public function getPrivacycompletedexport()
    {
        $this->db->setQuery("select count(*) from #__privacy_requests where status = 2 and request_type = 'export'");

        return $this->db->LoadResult();
    }

    public function getPrivacypendingexport()
    {
        $this->db->setQuery("select count(*) from #__privacy_requests where status = 0 and request_type = 'export'");

        return $this->db->LoadResult();
    }

    public function getPrivacycompletedremove()
    {
        $this->db->setQuery("select count(*) from #__privacy_requests where status = 2 and request_type = 'remove'");

        return $this->db->LoadResult();
    }

    /**
     * Get the overdue requests.
     *
     * @return bool
     */
    public function getPrivacyoverdue()
    {
        // Load the parameters.
        $params = ComponentHelper::getComponent('com_privacy')->getParams();
        $notify = (int) $params->get('notify', 14);
        $now    = Factory::getDate()->toSql();
        $period = '-' . $notify;

        $query = $this->db->getQuery(true)
            ->select('COUNT(*)');
        $query->from($this->db->quoteName('#__privacy_requests'));
        $query->where($this->db->quoteName('status') . ' = 1 ');
        $query->where($query->dateAdd($this->db->quote($now), $period, 'DAY') . ' > ' . $this->db->quoteName('requested_at'));
        $this->db->setQuery($query);

        return $this->db->LoadResult();
    }

    /**
     * Joomla 3.9.0+ Check for system log rotation plugin.
     */
    public function getSystemLogRotationEnabled()
    {
        $this->db->setQuery("SELECT count(*) FROM `#__extensions` WHERE `name` = 'plg_system_logrotation' and enabled = 1");

        return $this->db->LoadResult();
    }

    public function getGuidedToursEnabled()
    {
        $this->db->setQuery("SELECT count(*) FROM `#__extensions` WHERE `name` = 'plg_system_guidedtours' and enabled = 1");

        return $this->db->LoadResult();
    }

    /**
     * Joomla 3.9.0+ Check for action log ip logging enabled.
     */
    public function hasprivacypolicy()
    {
        $this->db->setQuery("SELECT params FROM `#__extensions` WHERE `name` = 'plg_system_privacyconsent'");

        $res = $this->db->LoadResult();

        if (! $res) {
            return 0;
        }

        $params = json_decode($res);

        if ($params && property_exists($params, 'privacy_article')) {
            return $params->privacy_article > 0 ? 1 : 0;
        }

        return 0;
    }

    /**
     * Joomla 3.9.0+ Check for action log ip logging enabled.
     */
    public function getActionLogsIPLoggingEnabled()
    {
        $this->db->setQuery("SELECT params FROM `#__extensions` WHERE `name` = 'com_actionlogs'");

        $params = json_decode($this->db->LoadResult());

        if ($params && property_exists($params, 'ip_logging')) {
            return $params->ip_logging;
        }

        return 0;
    }

    /**
     * Joomla 3.9.0+ Check for action log ip logging enabled.
     */
    public function getUseractionlogenabled()
    {
        $this->db->setQuery(
            "SELECT count(*) FROM `#__extensions` WHERE (`name` = 'PLG_ACTIONLOG_JOOMLA' or `name` = 'PLG_SYSTEM_ACTIONLOGS') and enabled = 1"
        );

        return 2 == $this->db->LoadResult() ? 1 : 0;
    }

    /**
     * Joomla 3.9.0+ Check for plg_privacy_actionlogs enabled.
     */
    public function getPrivacyConsentPluginEnabled()
    {
        $this->db->setQuery("SELECT count(*) FROM `#__extensions` WHERE `name` = 'plg_system_privacyconsent' and enabled = 1");

        return $this->db->LoadResult();
    }

    /**
     * Checks if the FTP Layer is in anyway configured.
     *
     * @return bool
     */
    private function checkFTPLayer()
    {
        $ftp_pass   = $this->config->get('ftp_pass', '');
        $ftp_user   = $this->config->get('ftp_user', '');
        $ftp_enable = $this->config->get('ftp_enable', '');
        $ftp_host   = $this->config->get('ftp_host', '');
        $ftp_root   = $this->config->get('ftp_root', '');

        if ($ftp_pass || $ftp_user || '1' == $ftp_enable || $ftp_host || $ftp_root) {
            return true;
        }

        return false;
    }

    /**
     * Clean up old mysites.guru files and features.
     */
    private function cleanOurCrap()
    {
        // cleanup old files
        $oldFiles = [
            'upgrade.zip',
            './bfViewLog.php',
            './bfDev.php',
            './bfMysql.php',
            './j25_30_bfnetwork.xml', // dont get confused with the one in the folder above this.
            './install.bfnetwork.php',
            './bfnetwork.xml',
            './bfJson.php',
            './tmp/log.tmp',
            './tmp/tmp.ob',
        ];

        foreach ($oldFiles as $file) {
            if (file_exists($file)) {
                @unlink($file);
            }
        }

        // cleanup
        if (file_exists('../j25_30_bfnetwork.xml')) {
            @copy('../j25_30_bfnetwork.xml', '../bfnetwork.xml');
            @unlink('../j25_30_bfnetwork.xml');
        }

        $fileContent = file_get_contents('../bfnetwork.php');
        if (! preg_match('/bfPlugin/', $fileContent)) {
            $fileContent = str_replace([
                "\n\n",
                '// For more details please contact Phil Taylor <[email protected]>',
                '// This is NOT a Joomla Extension or Plugin and is NOT designed for consumption within Joomla - yet :)', ], '', $fileContent);
            $fileContent = $fileContent . "
/**
 * All our code is in the sub folder, as that is what is auto-upgraded
 * and fully maintained by the automated processes at mysites.guru
 */
require 'bfnetwork/bfPlugin.php';";

            file_put_contents('../bfnetwork.php', $fileContent);
        }

        bfActivitylog::getInstance();
    }

    /**
     * Init the Joomla db connection.
     */
    private function initDb()
    {
        try {
            $this->db = $this->container->get('DatabaseDriver');

            if (! $conn = $this->db->getConnection()) {
                $this->db->connect();
                $conn = $this->db->getConnection();
            }

            if (! $conn) {
                return '';
            }

            if (get_class($conn) === \PDO::class) {
                $dbVerString = $conn->getAttribute(\PDO::ATTR_SERVER_VERSION);
            } else {
                $dbVerString = $conn->server_info;
            }
        } catch (\Exception $exception) {
            $dbVerString = '';
        }

        return $dbVerString;
    }

    private function getJoomlaVersion()
    {
        $VERSION = new Version();

        // Store in our object for switching configs
        $this->version = $VERSION->getShortVersion();

        return $VERSION->getShortVersion();
    }

    /**
     * How many databases can I see?
     *
     * We need to reconnect again to the db so we are ot going through the Joomla DB Layer because it just crashes too
     * far up the stack for us to catch the exception
     *
     * @return int
     */
    private function getVisibleDbsCount()
    {
        if (! function_exists('mysqli_connect')) {
            return 1;
        }

        $count = 0;
        try {
            // Create correct commands based on how old and crap the server is!
            switch ($this->config->get('dbtype')) {
                default:
                case \mysqli::class:
                    $port = '3306';

                    // Handle localhost:3306 type hosts
                    $parts = explode(':', $this->config->get('host'));

                    if (\count($parts) > 1) {
                        $port = $parts[1];
                    } else {
                        $port = null;
                    }

                    $link = mysqli_connect($parts[0], $this->config->get('user'), $this->config->get('password'), null, $port);
                    if (! $link) {
                        return 0;
                    }

                    $res = mysqli_query(
                        $link,
                        'SHOW DATABASES where `Database` NOT IN ("test","performance_schema", "information_schema", "mysql")'
                    );

                    if (! $res) {
                        return 0;
                    }

                    $count = $res->num_rows;

                    // tidy up
                    mysqli_close($link);
                    break;
            }

            // return number seen
            return $count;
        } catch (Exception $e) {
            return $count;
        }
    }

    /**
     * Do we have any backup tables.
     *
     * @return string
     */
    private function hasBakTables()
    {
        $this->db->setQuery("SHOW TABLES WHERE `Tables_in_{$this->config->get('db', '')}` like 'bak_%'");

        return $this->db->loadResult() ? true : false;
    }

    /**
     * See if we have any installation folders.
     *
     * @return string "TRUE|FALSE" if we do
     */
    private function hasInstallationFolders()
    {
        $folders = $this->getFolders(JPATH_BASE);
        foreach ($folders as $folder) {
            if (preg_match(
                '/installation|installation.old|docs\/installation|install|installation.bak|installation.old|installation.backup|installation.delete/i',
                $folder,
                $matches
            )) {
                return true;
            }
        }

        return false;
    }

    /**
     * Function taken from Akeeba filesystem.php.
     *
     * Akeeba Engine The modular PHP5 site backup engine
     *
     * @copyright Copyright (c)2009 Nicholas K. Dionysopoulos
     * @license   GNU GPL version 3 or, at your option, any later version
     *
     * @version   Id: scanner.php 158 2010-06-10 08:46:49Z nikosdion
     */
    private function getFolders($folder)
    {
        // Initialize variables
        $arr   = [];
        $false = false;

        $folder = trim($folder);

        if (! is_dir($folder) && ! is_dir($folder . \DIRECTORY_SEPARATOR) || is_link($folder . \DIRECTORY_SEPARATOR) || is_link(
            $folder
        ) || ! $folder) {
            return $false;
        }

        if (@file_exists($folder . \DIRECTORY_SEPARATOR . '.myjoomla.ignore.folder')) {
            return [];
        }

        $handle = @opendir($folder);
        if (false === $handle) {
            $handle = @opendir($folder . \DIRECTORY_SEPARATOR);
        }
        // If directory is not accessible, just return FALSE
        if (false === $handle) {
            return $false;
        }

        while ((false !== ($file = @readdir($handle)))) {
            if (('.' != $file) && ('..' != $file) && (null != trim($file))) {
                $ds = ('' == $folder) || (\DIRECTORY_SEPARATOR == $folder) || (\DIRECTORY_SEPARATOR == @substr(
                    $folder,
                    -1
                )) || (\DIRECTORY_SEPARATOR == @substr($folder, -1)) ? '' : \DIRECTORY_SEPARATOR;
                $dir   = trim($folder . $ds . $file);
                $isDir = @is_dir($dir);
                if ($isDir) {
                    $arr[] = $this->cleanupFileFolderName(str_replace(JPATH_BASE, '', $folder . \DIRECTORY_SEPARATOR . $file));
                }
            }
        }
        @closedir($handle);

        return $arr;
    }

    /**
     * Clean up a string, a path name.
     *
     * @param string $str
     *
     * @return string
     */
    private function cleanupFileFolderName($str)
    {
        $str = str_replace('////', '/', $str);
        $str = str_replace('///', '/', $str);
        $str = str_replace('//', '/', $str);
        $str = str_replace('\\/', '/', $str);
        $str = str_replace('\\t', '/t', $str);
        $str = str_replace("\/", '/', $str);

        return addslashes($str);
    }

    /**
     * The the number of super admins.
     *
     * @return int The number of super admins
     * @todo remove hard coded 8 and look for the correct group_id if people have messed with ACL
     */
    private function getNumberOfSuperAdmins()
    {
        $this->db->setQuery('SELECT count(*) FROM #__user_usergroup_map WHERE group_id = 8');

        return (int) $this->db->LoadResult();
    }

    /**
     * Report if any users have a username of 'admin'.
     *
     * @return int
     */
    private function getAdminUserNameCount()
    {
        $this->db->setQuery('SELECT COUNT(*) FROM #__users WHERE username = "admin"');

        return (int) $this->db->LoadResult();
    }

    private function getNeverLoggedInUsersCount()
    {
        $this->db->setQuery('SELECT COUNT(*) FROM #__users WHERE lastvisitDate IS NULL');

        return (int) $this->db->LoadResult();
    }

    /**
     * See if we have extension installed.
     */
    private function hasExtensionWithNameInstalled($name)
    {
        $count   = 0;
        $folders = $this->getFolders(JPATH_BASE . '/administrator/components/');
        foreach ($folders as $folder) {
            if (preg_match('/' . $name . '/i', $folder, $matches)) {
                ++$count;
            }
        }

        return $count;
    }

    private function hastmplogfolderswritable()
    {
        return is_writable($this->config->get('tmp_path')) && is_writable($this->config->get('log_path'));
    }

    /**
     * @return bool
     */
    private function hasUsedDefaultTemplate()
    {
        $core_templates = [
            'atomic',
            'beez_20',
            'beez_5',
            'beez3',
            'ja_purity',
            'protostar',
            'rhuk_milkyway',
            'rhuk_milkyway_2',
            'cassiopeia',
        ];

        $this->db->setQuery('SELECT template FROM #__template_styles WHERE client_id=0 AND home=1');

        return (bool) in_array($this->db->loadResult(), $core_templates);
    }

    private function hastpequalsone()
    {
        if (1 == ComponentHelper::getParams('com_templates')
            ->get('template_positions_display')
        ) {
            // allowed - which is bad
            $tpequalsone = 1;
        } else {
            // not allowed - which is good
            $tpequalsone = 0;
        }

        return $tpequalsone;
    }

    private function kickstartexists()
    {
        $files = scandir(JPATH_BASE);
        foreach ($files as $file) {
            if (preg_match('/.*kickstart.*\.php/i', $file)) {
                return true;
            }
        }

        return false;
    }

    private function fpaexists()
    {
        $files = scandir(JPATH_BASE);
        foreach ($files as $file) {
            if (preg_match('/.*fpa.*\.php/i', $file)) {
                return true;
            }
        }

        return false;
    }

    private function getErrorReportingLevel()
    {
        $er = $this->config->get('error_reporting');
        if (! is_int($er)) {
            switch ($er) {
                case 'none':
                    $er = 0;
                    break;
                case 'simple':
                    $er = 7;
                    break;
                case 'maximum':
                    $er = 2047;
                    break;
                case 'development':
                    $er = -1;
                    break;
                default:
                    $er = $er; // yeah yeah I know!
                    break;
            }
        }

        return $er;
    }

    private function getNumberOfAkeebaBackups()
    {
        $count  = 0;
        $folder = JPATH_BASE . '/administrator/components/com_akeeba/backup';
        if (file_exists($folder)) {
            $folderContents = scandir($folder);

            foreach ($folderContents as $file) {
                if (preg_match('/\.jpa$/i', $file)) {
                    ++$count;
                }
            }
        }

        return $count;
    }

    private function hasmd5passwords()
    {
        $this->db->setQuery('SELECT count(*) FROM #__users WHERE CHAR_LENGTH(password) = 32');

        return (int) $this->db->LoadResult();
    }

    private function hastmplogfoldersdefaultpaths()
    {
        $logPath          = $this->config->get('log_path');
        $tmpPath          = $this->config->get('tmp_path');
        $expectedLogPath1 = JPATH_BASE . '/logs';
        $expectedLogPath2 = JPATH_BASE . '/administrator/logs'; // Introduced in Joomla 3.6.0
        $expectedTmpPath  = JPATH_BASE . '/tmp';

        return (int) (($expectedLogPath1 == $logPath || $expectedLogPath2 == $logPath) && $expectedTmpPath == $tmpPath);
    }

    private function getMaxAllowedPacket()
    {
        $this->db->setQuery('SHOW VARIABLES LIKE "max_allowed_packet"');
        $res = $this->db->loadObjectList();

        return $res[0]->Value;
    }

    /**
     * @return string
     */
    private function checkJCEVersion()
    {
        $versionFile = JPATH_BASE . '/administrator/components/com_jce/jce.xml';
        if (file_exists($versionFile)) {
            $xml = file_get_contents($versionFile);
            preg_match('/\<version\>(.*)\<\/version\>/', $xml, $matches);
            if (count($matches)) {
                return $matches[1];
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    private function checkfluff()
    {
        $fluffFiles = [
            '/.drone.yml',
            '/robots.txt.dist',
            '/web.config.txt',
            '/joomla.xml',
            '/build.xml',
            '/LICENSE.txt',
            '/README.txt',
            '/htaccess.txt',
            '/LICENSES.php',
            '/configuration.php-dist',
            '/CHANGELOG.php',
            '/COPYRIGHT.php',
            '/CREDITS.php',
            '/INSTALL.php',
            '/LICENSE.php',
            '/CONTRIBUTING.md',
            '/phpunit.xml.dist',
            '/README.md',
            '/.travis.yml',
            '/travisci-phpunit.xml',
            '/images/banners/osmbanner1.png',
            '/images/banners/osmbanner2.png',
            '/images/banners/shop-ad-books.jpg',
            '/images/banners/shop-ad.jpg',
            '/images/banners/white.png',
            '/images/headers/blue-flower.jpg',
            '/images/headers/maple.jpg',
            '/images/headers/raindrops.jpg',
            '/images/headers/walden-pond.jpg',
            '/images/headers/windows.jpg',
            '/images/joomla_black.gif',
            '/images/joomla_black.png',
            '/images/joomla_green.gif',
            '/images/joomla_logo_black.jpg',
            '/images/powered_by.png',
            '/images/sampledata/fruitshop/apple.jpg',
            '/images/sampledata/fruitshop/bananas_2.jpg',
            '/images/sampledata/fruitshop/fruits.gif',
            '/images/sampledata/fruitshop/tamarind.jpg',
            '/images/sampledata/parks/animals/180px_koala_ag1.jpg',
            '/images/sampledata/parks/animals/180px_wobbegong.jpg',
            '/images/sampledata/parks/animals/200px_phyllopteryx_taeniolatus1.jpg',
            '/images/sampledata/parks/animals/220px_spottedquoll_2005_seanmcclean.jpg',
            '/images/sampledata/parks/animals/789px_spottedquoll_2005_seanmcclean.jpg',
            '/images/sampledata/parks/animals/800px_koala_ag1.jpg',
            '/images/sampledata/parks/animals/800px_phyllopteryx_taeniolatus1.jpg',
            '/images/sampledata/parks/animals/800px_wobbegong.jpg',
            '/images/sampledata/parks/banner_cradle.jpg',
            '/images/sampledata/parks/landscape/120px_pinnacles_western_australia.jpg',
            '/images/sampledata/parks/landscape/120px_rainforest_bluemountainsnsw.jpg',
            '/images/sampledata/parks/landscape/180px_ormiston_pound.jpg',
            '/images/sampledata/parks/landscape/250px_cradle_mountain_seen_from_barn_bluff.jpg',
            '/images/sampledata/parks/landscape/727px_rainforest_bluemountainsnsw.jpg',
            '/images/sampledata/parks/landscape/800px_cradle_mountain_seen_from_barn_bluff.jpg',
            '/images/sampledata/parks/landscape/800px_ormiston_pound.jpg',
            '/images/sampledata/parks/landscape/800px_pinnacles_western_australia.jpg',
            '/images/sampledata/parks/parks.gif',
        ];

        $fluffCount = 0;
        foreach ($fluffFiles as $file) {
            $fileWithPath = JPATH_BASE . $file;
            if (file_exists($fileWithPath)) {
                ++$fluffCount;
            }
        }

        return (int) $fluffCount;
    }

    private function checkdbschema()
    {
        /** @var DatabaseModel $model */
        $model = Factory::getApplication()
            ->bootComponent('com_installer')
            ->getMVCFactory()
            ->createModel('Database', 'Administrator', [
                'ignore_request' => true,
            ]);

        $schemaData = new stdClass();

        // Force sensible defaults to stop Joomla, with PHP 8+, and Error Reporting Maximum - from showing Deprecated warnings
        $model->setState('list.limit', 1000);
        $model->setState('list.start', 0);
        $model->setState('filter.search', '');

        foreach ($model->getItems() as $item) {
            if ('com_admin' !== $item['extension']->element) {
                continue;
            }
            $schemaData->version_latest  = $item['extension']->version;
            $schemaData->version_current = JVERSION;
        }

        $changeSet = new ChangeSet($this->db, null);

        $this->db->setQuery('select extension_id from #__extensions where name = "files_joomla"');
        $filesJoomlaId = $this->db->loadResult();

        $schemaData->latest  = $changeSet->getSchema();
        $schemaData->current = $model->getSchemaVersion($filesJoomlaId);

        return json_encode($schemaData);
    }

    private function checkRobotsBlocksMedia()
    {
        $robots_blocks_media = 0;

        if (file_exists(JPATH_BASE . '/robots.txt')) {
            $robotsTxTContent = file_get_contents(JPATH_BASE . '/robots.txt');

            if (preg_match('/Disallow:\s\/(templates|media)\//', $robotsTxTContent)) {
                $robots_blocks_media = 1;
            }
        }

        return $robots_blocks_media;
    }

    private function getDiskSpace()
    {
        if (! function_exists('disk_free_space') || ! function_exists('disk_total_space')) {
            return json_encode([]);
        }

        $data = [
            'free'  => disk_free_space(JPATH_BASE),
            'total' => disk_total_space(JPATH_BASE),
        ];

        $data['used'] = $data['total'] - $data['free'];

        $data['percentUsed'] = sprintf('%.2f', ($data['used'] / $data['total']) * 100);

        $data['free']  = $this->formatSize($data['free']);
        $data['total'] = $this->formatSize($data['total']);
        $data['used']  = $this->formatSize($data['used']);

        return json_encode($data);
    }

    private function formatSize($bytes)
    {
        $types = ['B', 'KB', 'MB', 'GB', 'TB'];
        for ($i = 0; $bytes >= 1024 && $i < (count($types) - 1); $bytes /= 1024, $i++);

        return round($bytes, 2) . ' ' . $types[$i];
    }

    /**
     * Run some very specific checks to see if this site is hacked or not.
     */
    private function checkIf100percentHackedOrNot()
    {
        // oh, not dont this yet :) doing it service site instead :)
    }

    private function getNewUserType()
    {
        $this->db->setQuery("SELECT params FROM #__extensions WHERE name ='com_users'");
        $paramsJsonString = $this->db->loadResult();
        preg_match('/new_usertype\":\"([0-9]*)\"/', $paramsJsonString, $matches);

        return count($matches) ? $matches[1] : null;
    }

    private function getNon2FaAdmins()
    {
        if (version_compare($this->getJoomlaVersion(), '4.2.0') >= 0) {
            $this->db->setQuery("
                select * from #__users as u
                left join #__user_usergroup_map as ugm on ugm.user_id = u.id
                WHERE ugm.group_id IN 
                      (
                        select id from #__usergroups where title = 'Super Users' or title = 'Super Utilisateur'
                      )
                ");
            $superUsers   = $this->db->loadObjectList();
            $Non2FaAdmins = \count($superUsers);
            foreach ($superUsers as $user) {
                if (\count(\Joomla\Component\Users\Administrator\Helper\Mfa::getUserMfaRecords($user->id))) {
                    $Non2FaAdmins--;
                }
            }

            return $Non2FaAdmins;
        } else {
            try {
                $this->db->setQuery("select count(*) from #__users as u
                              left join #__user_usergroup_map as ugm on ugm.user_id = u.id
                              where (otpKey = \"\"  or otpKey IS NULL)
                             and (ugm.group_id IN (select id from #__usergroups where (title = 'Super Users' or title = 'Super Utilisateur')))");

                return $this->db->loadResult();
            } catch (\Exception $e) {
                return 0;
            }
        }
    }

    /**
     * Check for joomla.user.helper.XXXXX usernames - hack seen in Q4 2016.
     */
    private function checkJoomlaUserHelperHack2016()
    {
        $this->db->setQuery("select count(*) from #__users where username LIKE 'joomla.user.helper.%'");

        return $this->db->loadResult();
    }

    /**
     * Check the session gc plugin in Joomla 3.
     *
     * @return int
     */
    public function getSessionGCStatus()
    {
        $res = 2;

        // Session GC
        $this->db->setQuery("select count(*) from #__extensions where name = 'plg_system_sessiongc'");
        $hasSessionGcPlugin = $this->db->LoadResult();

        if ($hasSessionGcPlugin) {
            $this->db->setQuery("select enabled from #__extensions where name = 'plg_system_sessiongc'");
            $res = $this->db->LoadResult();
        }

        return $res;
    }

    /**
     * Check how many Two Factor Plugins are enabled.
     */
    public function getTwoFactorPluginsEnabled()
    {
        // Session GC
        $this->db->setQuery("SELECT count(*) FROM `#__extensions` WHERE `folder` = 'twofactorauth' and enabled = 1");

        return $this->db->LoadResult();
    }

    /**
     * Load filters from com_config without using a helper.
     */
    public function getAdminFilterFixed()
    {
        $this->db->setQuery("select params from #__extensions where element = 'com_config'");
        $params = json_decode($this->db->LoadResult());

        if ('NONE' == $params->filters->{7}->filter_type) {
            return 0;
        }
        if ('BL' == $params->filters->{7}->filter_type) {
            return 1;
        } else {
            return 2;
        }
    }

    /**
     * Load filters from com_config without using a helper.
     */
    public function getUserFilterFixed()
    {
        $this->db->setQuery("select params from #__extensions where element = 'com_config'");
        $params = json_decode($this->db->LoadResult());

        if ('NH' != @$params->filters->{1}->filter_type) {
            return 0;
        }
        if ('NH' != @$params->filters->{2}->filter_type) {
            return 0;
        }
        if ('NH' != @$params->filters->{9}->filter_type) {
            return 0;
        }

        return 1;
    }

    /**
     * Load sendpassword from params from com_users without using a helper.
     */
    public function getPlaintextpasswordsFixed()
    {
        $this->db->setQuery("select params from #__extensions where element = 'com_users'");
        $params = json_decode($this->db->LoadResult());

        return 1 - $params->sendpassword;
    }

    /**
     * Load Flash Upload Settings from params from com_media without using a helper.
     */
    public function getUploadsettingsfixed()
    {
        $this->db->setQuery("select params from #__extensions where element = 'com_media'");
        $res = $this->db->LoadResult();

        if (! $res) {
            return 0;
        }

        $params = json_decode($res);
        if (! $params || ! property_exists($params, 'upload_extensions')) {
            return 0;
        }

        if (
            ! preg_match('/swf/ism', $params->upload_extensions)
            &&
            ! preg_match('/application\/x-shockwave-flash/ism', $params->upload_mime)
        ) {
            return 1;
        } else {
            return 0;
        }
    }

    /**
     * Get the configuration of the google recaptcha plugin and global config.
     */
    private function getCaptchaDetails()
    {
        $this->db->setQuery(
            "SELECT count(*) FROM #__extensions WHERE (name ='plg_captcha_recaptcha' or name = 'plg_captcha_recaptcha_invisible') and enabled = 1"
        );

        return 0 != $this->db->loadResult() ? 1 : 0;
    }

    public function getData()
    {
        return $this->_data;
    }

    private function hasUpdatesAvailable()
    {
        set_time_limit(60);
        ob_start();
        require 'bfUpdates.php';
        $upCheck                   = new bfUpdates($this->db);
        $extensionupdatesavailable = $upCheck->getUpdates(true);
        // remove any stray output
        echo ' '; // must have something to clean else warning occurs
        @ob_clean();

        return $extensionupdatesavailable;
    }
}

$data = new bfSnapshot();
bfEncrypt::reply(bfReply::SUCCESS, $data->getData());

© 2025 Cubjrnet7