Spamworldpro Mini Shell
Spamworldpro


Server : Apache
System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64
User : corals ( 1002)
PHP Version : 7.4.33
Disable Function : exec,passthru,shell_exec,system
Directory :  /home/corals/old/vendor/mirasvit/module-search-ultimate/src/SearchSphinx/Model/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/corals/old/vendor/mirasvit/module-search-ultimate/src/SearchSphinx/Model/Engine.php
<?php
/**
 * Mirasvit
 *
 * This source file is subject to the Mirasvit Software License, which is available at https://mirasvit.com/license/.
 * Do not edit or add to this file if you wish to upgrade the to newer versions in the future.
 * If you wish to customize this module for your needs.
 * Please refer to http://www.magentocommerce.com for more information.
 *
 * @category  Mirasvit
 * @package   mirasvit/module-search-ultimate
 * @version   2.2.35
 * @copyright Copyright (C) 2024 Mirasvit (https://mirasvit.com/)
 */



namespace Mirasvit\SearchSphinx\Model;

use Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory as AttributeCollectionFactory;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\Directory\WriteFactory;
use Magento\Framework\Serialize\Serializer\Json;
use Magento\Store\Model\StoreManagerInterface;
use Mirasvit\Search\Api\Data\IndexInterface;
use Mirasvit\Search\Repository\IndexRepository;
use Mirasvit\Search\Service\IndexService;
use Mirasvit\SearchMysql\SearchAdapter\Index\IndexNameResolver;
use Mirasvit\SearchSphinx\Helper\Data as Helper;
use Mirasvit\SearchSphinx\SphinxQL\Connection;
use Mirasvit\SearchSphinx\SphinxQL\SphinxQL;

/**
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class Engine
{
    private $config;

    private $helper;

    private $indexRepository;

    private $indexService;

    private $storeManager;

    private $directory;

    private $basePath;

    private $configFilePath;

    private $absConfigFilePath;

    private $host;

    private $port;

    private $connection;

    private $lastStatusCheck     = 0;

    private $productAttributeCollectionFactory;

    private $availableAttributes = [];

    private $searchdCommand;

    private $indexNameResolver;

    private $serializer;

    public function __construct(
        Filesystem                 $fs,
        WriteFactory               $writeFactory,
        Config                     $config,
        Helper                     $helper,
        IndexRepository            $indexRepository,
        IndexService               $indexService,
        IndexNameResolver          $indexNameResolver,
        StoreManagerInterface      $storeManager,
        Json                       $serializer,
        AttributeCollectionFactory $productAttributeCollectionFactory
    ) {
        $this->config                            = $config;
        $this->helper                            = $helper;
        $this->indexRepository                   = $indexRepository;
        $this->indexService                      = $indexService;
        $this->indexNameResolver                 = $indexNameResolver;
        $this->storeManager                      = $storeManager;
        $this->serializer                        = $serializer;
        $this->productAttributeCollectionFactory = $productAttributeCollectionFactory;

        $this->directory = $fs->getDirectoryWrite(DirectoryList::VAR_DIR);

        if ($this->config->getCustomBasePath()) {
            $this->basePath  = rtrim($this->config->getCustomBasePath());
            $this->directory = $writeFactory->create('/');
        } else {
            $this->basePath = $fs->getDirectoryRead(DirectoryList::VAR_DIR)->getRelativePath('sphinx');
        }

        $this->configFilePath = $this->basePath . DIRECTORY_SEPARATOR . 'sphinx.conf';

        $this->absConfigFilePath = $this->directory->getAbsolutePath($this->configFilePath);

        $this->host = $this->config->getHost();
        $this->port = $this->config->getPort();

        // check all paths
        foreach ($this->config->getBinPath() as $binPath) {
            $this->searchdCommand = $binPath;
            try {
                if ($this->isAvailable()) {
                    break;
                }
            } catch (\LogicException $e) {
                $message = $e->getMessage();
            } catch (\Exception $e) {
                $message = $e->getMessage();
            }
        }

        $this->connection = new Connection();
        $this->connection->setParams([
            'host' => $this->host,
            'port' => $this->port,
        ]);

        if (file_exists($this->absConfigFilePath . '.attr')) {
            $this->availableAttributes = $this->serializer->unserialize(file_get_contents($this->absConfigFilePath . '.attr'));
        }
    }

    public function isAvailable(string &$output = ''): bool
    {
        /** mp uncomment start
         * return true;
         * mp uncomment end **/
        if ($this->config->isSameServer() == false) {
            return true;
        }

        $proceed = false;
        $path    = $this->directory->getAbsolutePath($this->configFilePath);
        if ($this->configFilePath && file_exists($path)) {
            $command = "$this->searchdCommand --status -c $path ";
            $exec    = $this->helper->exec($command);
            $proceed = strpos($exec['data'], 'uptime') !== false;
        }

        if (!$proceed) {
            $command = "$this->searchdCommand --config fake.conf 2>&1";
            $exec    = $this->helper->exec($command);
            $proceed = strpos($exec['data'], 'failed to parse config file') !== false;
        }

        if ($proceed) {
            $command     = "ps aux | grep searchd | awk '{print $13;}'";
            $exec        = $this->helper->exec($command);
            $configFiles = [];
            foreach (explode(PHP_EOL, $exec['data']) as $value) {
                if (strripos($value, 'sphinx.conf') !== false) {
                    $configFiles[] = $value;
                }
            }
            $configFiles = array_unique($configFiles);
            $ports       = [];
            foreach ($configFiles as $configFile) {
                if ($configFile == $this->directory->getAbsolutePath($this->configFilePath)) {
                    continue;
                }

                try {
                    $config = file_get_contents($configFile);
                    foreach (explode(PHP_EOL, $config) as $row) {
                        if (strripos($row, 'listen') !== false) {
                            foreach (explode(':', $row) as $data) {
                                if (is_numeric($data)) {
                                    $ports[] = (int)$data;
                                }
                            }
                        }
                    }
                } catch (\Exception $e) {
                }
            }

            if (in_array($this->port, $ports)) {
                $output .= __('Searchd already using the following config file(s) : ' . PHP_EOL . implode('-' . PHP_EOL, $configFiles) . PHP_EOL);
                $output .= __('Please make sure you use different sphinx ports for all of these instances.');

                return false;
            }

            return true;
        } else {
            $output .= __('Searchd not found at %1', $this->searchdCommand);

            return false;
        }
    }

    public function saveDocuments(IndexInterface $index, string $indexName, array $documents): void
    {
        foreach ($documents as $id => $document) {
            if (empty($id)) {
                continue;
            }

            $query = $this->getQuery()->replace()
                ->into($indexName)
                ->value('id', $id);

            if (isset($document['_instant'])) {
                $query->value('`autocomplete`', json_encode($document['_instant']));
                unset($document['_instant']);
            }

            if (isset($document['price_0_1'])) {
                $query->value('`price`', (float)$document['price_0_1']);
                $query->value('`price_string`', (string)number_format((float)$document['price_0_1'], 2, '', ''));
                unset($document['price_0_1']);
            }

            foreach ($document as $attr => $value) {
                if (isset($this->availableAttributes[$indexName])
                    && !array_key_exists($attr, $this->availableAttributes[$indexName])) {
                    unset($document[$attr]);
                    continue;
                }

                $attributeType = $this->availableAttributes[$indexName][$attr];

                $value = (!is_array($value) && strripos($attributeType, 'rt_attr_multi') !== false) ? [$value] : $value;

                $query->value('`' . $attr . '`', $value);
            }

            try {
                $query->execute();
            } catch (\Exception $e) {
                if (str_contains($e->getMessage(), 'no such index')) {
                    if ($this->config->isSameServer()) {
                        throw new \LogicException((string)__('Please reset and restart your sphinx daemon to search by new index'));
                    } else {
                        throw new \LogicException((string)__('Please generate a new configuration file'
                            . ' and place it to your remote server to search by new index'));
                    }
                } elseif (str_contains($e->getMessage(), 'unknown column')) {
                    throw new \LogicException((string)__('Please reset and restart your sphinx daemon to apply changes to search index'));
                } else {
                    throw new \LogicException('Please reset and restart your sphinx daemon. Current error is: ' . $e->getMessage());
                }
            }
        }
    }

    public function getQuery(): SphinxQL
    {
        return new SphinxQL($this->getConnection());
    }

    public function status(string &$output = ''): bool
    {
        if ($this->config->isSameServer() == false) {
            return true;
        }

        if (!$this->isAvailable($output)) {
            return false;
        }

        $output = '';

        $command = "$this->searchdCommand --config $this->absConfigFilePath --status";
        try {
            $exec = $this->helper->exec($command);
        } catch (\LogicException $e) {
            return true;
        }

        $output .= $exec['data'] . PHP_EOL;

        $command = "ps aux | grep searchd | awk '{print $2,$9,$11,$12,$13;}'";
        $exec    = $this->helper->exec($command);

        $output .= $exec['data'] . PHP_EOL;

        if (strpos($output, 'failed to connect to') !== false) {
            return false;
        }

        if (strpos($output, 'searchd status') === false) {
            return false;
        }

        if (strpos($output, 'uptime:') === false) {
            return false;
        }

        return true;
    }

    public function start(string &$output = ''): bool
    {
        if ($this->config->isSameServer() == false) {
            return true;
        }

        if (!$this->isAvailable($output)) {
            return false;
        }

        $this->makeConfig();

        $command = "$this->searchdCommand --config $this->absConfigFilePath";
        $exec    = $this->helper->exec($command);

        $output .= $exec['data'];

        if ($exec['status'] === 0) {
            return true;
        } else {
            return false;
        }
    }

    public function makeConfig(): string
    {
        if (!$this->directory->isExist($this->basePath)) {
            $this->directory->create($this->basePath);
            $this->directory->changePermissions($this->basePath, 0777);
        }

        $jsonData = [];

        $sphinxData = [
            'time'          => date('d.m.Y H:i:s'),
            'host'          => $this->host,
            'port'          => $this->port,
            'fallback_port' => $this->port - 1,
            'logdir'        => $this->directory->getAbsolutePath($this->basePath),
            'sphinxdir'     => $this->directory->getAbsolutePath($this->basePath),
            'indexes'       => '',
            'localdir'      => dirname(dirname(__FILE__)),
            'custom'        => $this->config->getAdditionalSearchdConfig(),
        ];

        $sphinxTemplate = $this->config->getSphinxConfigurationTemplate();
        $indexTemplate  = $this->config->getSphinxIndexConfigurationTemplate();

        foreach ($this->indexRepository->getCollection() as $index) {
            $instance = $this->indexRepository->getInstance($index);

            foreach (array_keys($this->storeManager->getStores()) as $storeId) {
                $indexName    = $this->indexNameResolver->getIndexNameByStoreId($instance->getIdentifier(), $storeId);
                $charsetTable = $this->config->getCustomCharsetTable();
                if (!$charsetTable) {
                    $charsetTable = $this->config->getDefaultCharsetTable();
                }

                $data = [
                    'name'          => $indexName,
                    'min_word_len'  => 1,
                    'path'          => $this->directory->getAbsolutePath($this->basePath) . '/' . $indexName,
                    'custom'        => $this->config->getAdditionalIndexConfig(),
                    'charset_table' => $charsetTable,
                ];

                $attributes = [];
                foreach (array_keys($instance->getAttributes()) as $attribute) {
                    $attributes[$attribute] = "    rt_field = $attribute";
                }

                if ($instance->getIdentifier() == 'catalogsearch_fulltext') {
                    $filterableAttributes = $this->getFilterableAttributes();
                    foreach ($filterableAttributes as $attribute => $type) {
                        $attributes[$attribute] = "    rt_attr_$type = $attribute";
                    }
                    for ($i =0;$i < 10000; $i++) {
                        $attribute = 'position_category_'.$i;
                        $attributes[$attribute] = "    rt_attr_bigint = $attribute";;
                    }
                }


                $data['attributes'] = implode(PHP_EOL, $attributes);

                $sphinxData['indexes'] .= $this->helper->filterTemplate($indexTemplate, $data);

                $jsonData[$indexName] = $attributes;
            }
        }

        $config = $this->helper->filterTemplate($sphinxTemplate, $sphinxData);

        if ($this->directory->isWritable($this->basePath)) {
            $this->directory->writeFile($this->configFilePath, $config);
            $this->directory->writeFile($this->configFilePath . '.attr', json_encode($jsonData));
        } else {
            if ($this->directory->isExist($this->configFilePath)) {
                throw new \LogicException((string)__('File %1 is not writable', $this->configFilePath));
            } else {
                throw new \LogicException((string)__('Directory %1 is not writable', $this->basePath));
            }
        }

        return $this->directory->getAbsolutePath($this->configFilePath);
    }

    public function deleteDocuments(IndexInterface $index, string $indexName, array $documents): void
    {
        if (!$this->status() && $this->config->isAutoRestartAllowed()) {
            $this->start();
        }

        foreach ($documents as $document) {
            $this->getQuery()
                ->delete()
                ->from($indexName)
                ->where('id', '=', $document)
                ->execute();
        }
    }

    public function cleanIndex(string $indexName): void
    {
        if (!$this->status() && $this->config->isAutoRestartAllowed()) {
            $this->start();
        }

        $this->getQuery()
            ->delete()
            ->from($indexName)
            ->where('id', '>', 0)
            ->execute();
    }

    public function restart(string &$output = ''): bool
    {
        if ($this->config->isSameServer() == false) {
            return true;
        }

        if (!$this->isAvailable($output)) {
            return false;
        }

        $this->stop($output);

        return $this->start($output);
    }

    public function stop(string &$output = ''): bool
    {
        if ($this->config->isSameServer() == false) {
            return true;
        }

        if (!$this->isAvailable($output)) {
            return false;
        }

        // first attempt (normal)
        $command = $this->searchdCommand . ' --config ' . $this->absConfigFilePath . ' --stopwait';
        $exec    = $this->helper->exec($command);
        $output  .= $exec['data'];

        // second attempt (forced)
        $find = "ps aux | grep searchd | grep $this->absConfigFilePath  | awk '{print $2}'";
        $pids = $this->helper->exec($find);
        foreach (explode(PHP_EOL, $pids['data']) as $id) {
            $command = "kill -9 $id";
            $this->helper->exec($command);
        }

        if ($exec['status'] === 0) {
            return true;
        } else {
            return false;
        }
    }

    public function reset(string &$output = ''): bool
    {
        if ($this->config->isSameServer() == false) {
            return true;
        }

        $this->stop($output);

        $path = $this->directory->getAbsolutePath($this->basePath);

        if (!preg_match('/\/var\/sphinx[\/]*$/', $path)) {
            $output = __('Please correct your Custom Base Path, it should end with "var/sphinx"');

            return false;
        }

        $command = "rm -rf {$path}/*";
        $exec    = $this->helper->exec($command);
        $output  .= $exec['data'];

        return true;
    }

    public function getAbsConfigFilePath(): string
    {
        return $this->absConfigFilePath;
    }

    private function getConnection(): Connection
    {
        if (microtime(true) - $this->lastStatusCheck < 20) {
            return $this->connection;
        }
        $this->lastStatusCheck = microtime(true);
        if (!$this->status() && $this->config->isAutoRestartAllowed()) {
            $this->start();
        }

        try {
            $this->connection->getConnection();
            $this->connection->ping();
        } catch (\Exception $e) {
            try {
                $this->connection->close();
            } catch (\Exception $e) {
            }
            $attempts = 0;
            $success  = false;
            while ($attempts < 20 && $success == false) {
                try {
                    $this->connection->connect();
                    $this->connection->ping();
                    $success = true;
                } catch (\Exception $e) {
                    $attempts++;
                }
            }
        }

        $this->connection->ping();

        return $this->connection;
    }

    private function getFilterableAttributes()
    {
        $filterableAttributes = $this->productAttributeCollectionFactory->create()
            ->addFieldToFilter(['is_filterable', 'is_required', 'is_global', 'used_in_product_listing', 'used_for_sort_by'],
                [
                    ['eq' => 1],
                    ['eq' => 1],
                    ['eq' => 1],
                    ['eq' => 1],
                    ['eq' => 1],
                ]
            );
        //            ->addFieldToFilter('is_searchable', 0);

        $result = [];
        foreach ($filterableAttributes as $attribute) {
            $type = 'multi';
            switch ($attribute->getFrontendInput()) {
                case 'boolean':
                    $type = 'bool';
                    break;
                case 'price':
                    $type = 'float';
                    break;
                case 'text':
                    $type = 'string';
                    break;
                case 'textarea':
                    $type = 'string';
                    break;
                case 'date':
                    $type = 'string';
                    break;
                case 'select':
                    $type = 'multi';
                    break;
                case 'multiselect':
                    $type = 'multi';
                    break;
            }

            $result[$attribute->getAttributeCode()] = $type;
        }

        $result['status']       = 'uint';
        $result['visibility']   = 'uint';
        $result['category_ids'] = 'multi';
        $result['price_string'] = 'string';

        return $result;
    }
}

Spamworldpro Mini