Skip to content
Snippets Groups Projects
MetaGer.php 64.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • use Illuminate\Support\Facades\Redis;
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
    use LaravelLocalization;
    
    use Monospice\LaravelRedisSentinel\RedisSentinel;
    
    use Predis\Connection\ConnectionException;
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
        const FETCHQUEUE_KEY = "fetcher.queue";
    
    
        public $alteredQuery = "";
        public $alterationOverrideQuery = "";
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
        protected $test;
    
        protected $eingabe;
        protected $q;
        protected $page;
        protected $lang;
        protected $cache = "";
        protected $site;
    
        protected $time = 2000;
    
        private $urlBlacklist = [];
        protected $stopWords = [];
        protected $phrases = [];
        protected $engines = [];
    
        protected $totalResults = 0;
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
        protected $queryFilter = [];
        protected $parameterFilter = [];
    
        protected $warnings = [];
        protected $errors = [];
        protected $addedHosts = [];
    
        protected $availableFoki = [];
    
        protected $startCount = 0;
        protected $canCache = false;
    
        # Daten über die Abfrage$
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
        protected $useragent;
    
    Phil Höfer's avatar
    Phil Höfer committed
        protected $apiAuthorized = false;
    
        protected $next = [];
    
        # Konfigurationseinstellungen:
        protected $sumaFile;
        protected $mobile;
        protected $resultCount;
        protected $sprueche;
    
        protected $domainsBlacklisted = [];
    
        protected $adDomainsBlacklisted = [];
    
        protected $adUrlsBlacklisted = [];
    
    Aria's avatar
    Aria committed
        protected $enabledSearchengines = [];
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
        protected $verificationId;
        protected $verificationCount;
    
        protected $searchUid;
    
        protected $redisResultWaitingKey, $redisResultEngineList, $redisEngineResult, $redisCurrentResultList;
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
        public $starttime;
    
        public function __construct($hash = "")
    
            if (file_exists(config_path() . "/blacklistDomains.txt") && file_exists(config_path() . "/blacklistUrl.txt")) {
    
                $tmp = file_get_contents(config_path() . "/blacklistDomains.txt");
    
                $this->domainsBlacklisted = explode("\n", $tmp);
    
                $tmp = file_get_contents(config_path() . "/blacklistUrl.txt");
                $this->urlsBlacklisted = explode("\n", $tmp);
    
                Log::warning("Achtung: Eine, oder mehrere Blacklist Dateien, konnten nicht geöffnet werden");
    
            # Versuchen Blacklists einzulesen
            if (file_exists(config_path() . "/adBlacklistDomains.txt") && file_exists(config_path() . "/adBlacklistUrl.txt")) {
                $tmp = file_get_contents(config_path() . "/adBlacklistDomains.txt");
                $this->adDomainsBlacklisted = explode("\n", $tmp);
                $tmp = file_get_contents(config_path() . "/adBlacklistUrl.txt");
                $this->adUrlsBlacklisted = explode("\n", $tmp);
            } else {
                Log::warning("Achtung: Eine, oder mehrere Blacklist Dateien, konnten nicht geöffnet werden");
            }
    
            $dir = app_path() . "/Models/parserSkripte/";
            foreach (scandir($dir) as $filename) {
                $path = $dir . $filename;
                if (is_file($path)) {
    
                    require_once $path;
    
            try {
                Cache::has('test');
                $this->canCache = true;
            } catch (ConnectionException $e) {
                $this->canCache = false;
            }
    
            if ($hash === "") {
                $this->searchUid = md5(uniqid());
            } else {
                $this->searchUid = $hash;
            }
    
            $redisPrefix = "search";
            # This is a list on which the MetaGer process can do a blocking pop to wait for new results
            $this->redisResultWaitingKey = $redisPrefix . "." . $this->searchUid . ".ready";
            # This is a list of searchengines which have delivered results for this search
            $this->redisResultEngineList = $redisPrefix . "." . $this->searchUid . ".engines";
            # This is the key where the results of the engine are stored as well as some statistical data
            $this->redisEngineResult = $redisPrefix . "." . $this->searchUid . ".results.";
    
            # A list of all search results already delivered to the user (sorted of course)
            $this->redisCurrentResultList = $redisPrefix . "." . $this->searchUid . ".currentResults";
    
        # Erstellt aus den gesammelten Ergebnissen den View
    
        public function createView()
    
            # Hiermit werden die evtl. ausgewählten SuMas extrahiert, damit die Input-Boxen richtig gesetzt werden können
            $focusPages = [];
    
            foreach ($this->request->all() as $key => $value) {
    
                if (starts_with($key, 'engine_') && $value === 'on') {
                    $focusPages[] = $key;
    
            # Wir extrahieren alle notwendigen Variablen und geben Sie an unseren View:
    
            foreach ($this->results as $result) {
    
                $viewResults[] = get_object_vars($result);
            }
            # Wir müssen natürlich noch den Log für die durchgeführte Suche schreiben:
            $this->createLogs();
    
            if ($this->fokus === "bilder") {
                switch ($this->out) {
    
                        return view('resultpages.results_images')
    
                            ->with('results', $viewResults)
                            ->with('eingabe', $this->eingabe)
                            ->with('mobile', $this->mobile)
                            ->with('warnings', $this->warnings)
                            ->with('errors', $this->errors)
    
    Phil Höfer's avatar
    Phil Höfer committed
                            ->with('apiAuthorized', $this->apiAuthorized)
    
                            ->with('browser', (new Agent())->browser());
    
                        return view('resultpages.resultpage_images')
    
                            ->with('results', $viewResults)
                            ->with('eingabe', $this->eingabe)
                            ->with('mobile', $this->mobile)
                            ->with('warnings', $this->warnings)
                            ->with('errors', $this->errors)
    
    Phil Höfer's avatar
    Phil Höfer committed
                            ->with('apiAuthorized', $this->apiAuthorized)
    
                            ->with('browser', (new Agent())->browser())
    
                            ->with('quicktips', action('MetaGerSearch@quicktips', ["search" => $this->eingabe]))
    
                            ->with('focus', $this->fokus)
                            ->with('resultcount', count($this->results));
    
            } else {
                switch ($this->out) {
                    case 'results':
    
                            ->with('results', $viewResults)
                            ->with('eingabe', $this->eingabe)
                            ->with('mobile', $this->mobile)
                            ->with('warnings', $this->warnings)
                            ->with('errors', $this->errors)
    
    Phil Höfer's avatar
    Phil Höfer committed
                            ->with('apiAuthorized', $this->apiAuthorized)
    
                            ->with('browser', (new Agent())->browser())
                            ->with('fokus', $this->fokus);
    
                            ->with('results', $viewResults)
                            ->with('eingabe', $this->eingabe)
                            ->with('mobile', $this->mobile)
                            ->with('warnings', $this->warnings)
                            ->with('errors', $this->errors)
    
    Phil Höfer's avatar
    Phil Höfer committed
                            ->with('apiAuthorized', $this->apiAuthorized)
    
                            ->with('metager', $this)
                            ->with('suspendheader', "yes")
    
                            ->with('browser', (new Agent())->browser())
                            ->with('fokus', $this->fokus);
    
                    case 'rich':
    
                        return view('resultpages.metager3rich')
    
                            ->with('results', $viewResults)
    
                            ->with('eingabe', $this->eingabe)
                            ->with('mobile', $this->mobile)
                            ->with('warnings', $this->warnings)
                            ->with('errors', $this->errors)
    
    Phil Höfer's avatar
    Phil Höfer committed
                            ->with('apiAuthorized', $this->apiAuthorized)
    
                            ->with('metager', $this)
    
                            ->with('browser', (new Agent())->browser())
                            ->with('fokus', $this->fokus);
    
                    case 'rss20':
    
                        return view('resultpages.metager3resultsrss20')
    
                            ->with('results', $viewResults)
                            ->with('eingabe', $this->eingabe)
    
    Phil Höfer's avatar
    Phil Höfer committed
                            ->with('apiAuthorized', $this->apiAuthorized)
    
                            ->with('metager', $this)
    
                            ->with('resultcount', sizeof($viewResults))
                            ->with('fokus', $this->fokus);
    
                    case 'api':
    
    Phil Höfer's avatar
    Phil Höfer committed
                        return response()->view('resultpages.metager3resultsatom10', ['results' => $viewResults, 'eingabe' => $this->eingabe, 'metager' => $this, 'resultcount' => sizeof($viewResults), 'key' => $this->apiKey, 'apiAuthorized' => $this->apiAuthorized])->header('Content-Type', 'application/xml');
    
                    case 'atom10':
    
    Phil Höfer's avatar
    Phil Höfer committed
                        return response()->view('resultpages.metager3resultsatom10', ['results' => $viewResults, 'eingabe' => $this->eingabe, 'metager' => $this, 'resultcount' => sizeof($viewResults), 'key' => $this->apiKey, 'apiAuthorized' => true])
    
                            ->header('Content-Type', 'application/xml');
    
                        break;
    
                    case 'result-count':
    
                        # Wir geben die Ergebniszahl und die benötigte Zeit zurück:
                        return sizeof($viewResults) . ";" . round((microtime(true) - $this->starttime), 2);
    
                            ->with('mobile', $this->mobile)
                            ->with('warnings', $this->warnings)
                            ->with('errors', $this->errors)
    
    Phil Höfer's avatar
    Phil Höfer committed
                            ->with('apiAuthorized', $this->apiAuthorized)
    
                            ->with('browser', (new Agent())->browser())
    
                            ->with('quicktips', action('MetaGerSearch@quicktips', ["search" => $this->eingabe, "quotes" => $this->sprueche]))
    
                            ->with('resultcount', count($this->results))
                            ->with('focus', $this->fokus);
    
        public function prepareResults()
    
            $engines = $this->engines;
            // combine
    
            $this->combineResults($engines);
    
            // misc (WiP)
    
            if ($this->fokus == "nachrichten") {
    
                $this->results = array_filter($this->results, function ($v, $k) {
                    return !is_null($v->getRank());
                }, ARRAY_FILTER_USE_BOTH);
    
                uasort($this->results, function ($a, $b) {
                    $datea = $a->getDate();
                    $dateb = $b->getDate();
                    return $dateb - $datea;
                });
            } else {
                uasort($this->results, function ($a, $b) {
                    if ($a->getRank() == $b->getRank()) {
                        return 0;
                    }
    
                    return ($a->getRank() < $b->getRank()) ? 1 : -1;
                });
            }
    
            # Validate Results
            $newResults = [];
    
            foreach ($this->results as $result) {
                if ($result->isValid($this)) {
    
            # Validate Advertisements
            $newResults = [];
            foreach ($this->ads as $ad) {
                if (($ad->strippedHost !== "" && (in_array($ad->strippedHost, $this->adDomainsBlacklisted) ||
    
                    in_array($ad->strippedLink, $this->adUrlsBlacklisted))) || ($ad->strippedHostAnzeige !== "" && (in_array($ad->strippedHostAnzeige, $this->adDomainsBlacklisted) ||
                    in_array($ad->strippedLinkAnzeige, $this->adUrlsBlacklisted)))
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
                ) {
    
                    continue;
                }
                $newResults[] = $ad;
            }
            $this->ads = $newResults;
    
    
            #Adgoal Implementation
    
            if (!$this->apiAuthorized) {
                $this->results = $this->parseAdgoal($this->results);
            }
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            # Human Verification
            $this->results = $this->humanVerification($this->results);
    
            $this->ads = $this->humanVerification($this->ads);
    
            if (count($this->results) <= 0) {
    
                if (strlen($this->site) > 0) {
                    $no_sitesearch_query = str_replace(urlencode("site:" . $this->site), "", $this->fullUrl);
                    $this->errors[] = trans('metaGer.results.failedSitesearch', ['altSearch' => $no_sitesearch_query]);
                } else {
                    $this->errors[] = trans('metaGer.results.failed');
                }
    
            if ($this->canCache() && isset($this->next) && count($this->next) > 0 && count($this->results) > 0) {
    
                Cache::put($this->getSearchUid(), serialize($this->next), 60 * 60);
    
        public function combineResults($engines)
        {
            foreach ($engines as $engine) {
                if (isset($engine->next)) {
                    $this->next[] = $engine->next;
                }
                if (isset($engine->last)) {
                    $this->last[] = $engine->last;
                }
                foreach ($engine->results as $result) {
                    if ($result->valid) {
                        $this->results[] = $result;
                    }
                }
                foreach ($engine->ads as $ad) {
                    $this->ads[] = $ad;
                }
            }
        }
    
    
        public function parseAdgoal($results)
        {
    
            $privateKey = getenv('adgoal_private');
    
                    $link = $result->link;
    
                        $link = "http://" . $link;
                    }
                    $tldList .= parse_url($link, PHP_URL_HOST) . ",";
                    $result->tld = parse_url($link, PHP_URL_HOST);
                }
                $tldList = rtrim($tldList, ",");
    
                # Hashwert
                $hash = md5("meta" . $publicKey . $tldList . "GER");
    
    
                $query = $this->q;
    
                $link = "https://api.smartredirect.de/api_v2/CheckForAffiliateUniversalsearchMetager.php?p=" . urlencode($publicKey) . "&k=" . urlencode($hash) . "&tld=" . urlencode($tldList) . "&q=" . urlencode($query);
    
                $answer = json_decode(file_get_contents($link));
    
                # Nun müssen wir nur noch die Links für die Advertiser ändern:
    
                        if ($result->new && $hoster === $result->tld && !$result->partnershop) {
    
                            # Hier ist ein Advertiser:
                            # Das Logo hinzufügen:
    
                                $result->logo = "https://img.smartredirect.de/logos_v2/60x30/" . urlencode($hash) . ".gif";
    
                                $result->image = "https://img.smartredirect.de/logos_v2/120x60/" . urlencode($hash) . ".gif";
    
                            # Den Link hinzufügen:
                            $publicKey = $publicKey;
    
                            $targetUrl = $result->link;
    
                            $gateHash = md5($targetUrl . $privateKey);
    
                            $newLink = "https://api.smartredirect.de/api_v2/ClickGate.php?p=" . urlencode($publicKey) . "&k=" . urlencode($gateHash) . "&url=" . urlencode($targetUrl) . "&q=" . urlencode($query);
    
        public function humanVerification($results)
        {
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            # Let's check if we need to implement a redirect for human verification
    
            if ($this->verificationCount > 10) {
                foreach ($results as $result) {
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
                    $link = $result->link;
                    $day = Carbon::now()->day;
                    $pw = md5($this->verificationId . $day . $link . env("PROXY_PASSWORD"));
    
                    $url = route('humanverification', ['mm' => $this->verificationId, 'pw' => $pw, "url" => urlencode(str_replace("/", "<<SLASH>>", base64_encode($link)))]);
                    $proxyPw = md5($this->verificationId . $day . $result->proxyLink . env("PROXY_PASSWORD"));
                    $proxyUrl = route('humanverification', ['mm' => $this->verificationId, 'pw' => $proxyPw, "url" => urlencode(str_replace("/", "<<SLASH>>", base64_encode($result->proxyLink)))]);
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
                    $result->link = $url;
    
                    $result->proxyLink = $proxyUrl;
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
                }
                return $results;
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
                return $results;
            }
        }
    
    
    Phil Höfer's avatar
    Phil Höfer committed
        public function authorize($key)
        {
            $postdata = http_build_query(array(
                'dummy' => rand(),
            ));
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
            $opts = array(
                'http' => array(
                    'method' => 'POST',
                    'header' => 'Content-type: application/x-www-form-urlencoded',
                    'content' => $postdata,
                ),
    
    Phil Höfer's avatar
    Phil Höfer committed
            );
    
            $context = stream_context_create($opts);
    
            try {
    
                $link = "https://key.metager3.de/" . urlencode($key) . "/request-permission/api-access";
    
    Phil Höfer's avatar
    Phil Höfer committed
                $result = json_decode(file_get_contents($link, false, $context));
                if ($result->{'api-access'} == true) {
                    return true;
                } else {
                    return false;
                }
            } catch (\ErrorException $e) {
                return false;
            }
        }
    
    
    Karl's avatar
    Karl committed
        /*
         * Die Erstellung der Suchmaschinen bis die Ergebnisse da sind mit Unterfunktionen
         */
    
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
        public function createSearchEngines(Request $request, &$timings)
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            if (!empty($timings)) {
                $timings["createSearchEngines"]["start"] = microtime(true) - $timings["starttime"];
            }
    
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            if (!$request->filled("eingabe") || $this->q === "") {
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            $this->enabledSearchengines = [];
    
            # Check if selected focus is valid
            if (empty($this->sumaFile->foki->{$this->fokus})) {
                $this->fokus = "web";
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
            $sumaNames = $this->sumaFile->foki->{$this->fokus}->sumas;
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
            $sumas = [];
            foreach ($sumaNames as $sumaName) {
                $sumas[$sumaName] = $this->sumaFile->sumas->{$sumaName};
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            if (!empty($timings)) {
                $timings["createSearchEngines"]["created engine array"] = microtime(true) - $timings["starttime"];
            }
    
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
            $this->removeAdsFromListIfAdfree($sumas);
    
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            if (!empty($timings)) {
                $timings["createSearchEngines"]["removed ads"] = microtime(true) - $timings["starttime"];
            }
    
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
            foreach ($sumas as $sumaName => $suma) {
    
                # Check if this engine is disabled and can't be used
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
                $disabled = empty($suma->disabled) ? false : $suma->disabled;
                $autoDisabled = empty($suma->{"auto-disabled"}) ? false : $suma->{"auto-disabled"};
                if (
                    $disabled || $autoDisabled
                    || \Cookie::get($this->getFokus() . "_engine_" . $sumaName) === "off"
                ) {
                    continue;
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
    
                # Check if this engine can use potentially defined query-filter
                foreach ($this->queryFilter as $filterName => $filter) {
                    if (empty($this->sumaFile->filter->{"query-filter"}->$filterName->sumas->$sumaName)) {
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
    
                # Check if this engine can use potentially defined parameter-filter
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
                if ($valid) {
                    foreach ($this->parameterFilter as $filterName => $filter) {
    
                        # We need to check if the searchengine supports the parameter value, too
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
                        if (empty($filter->sumas->$sumaName) || empty($filter->sumas->{$sumaName}->values->{$filter->value})) {
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
                            $valid = false;
                            break;
                        }
                    }
                }
    
                # Check if this engine should only be active when filter is used
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
                if ($suma->{"filter-opt-in"}) {
    
                    # This search engine should only be used when a parameter filter of it is used
                    $validTmp = false;
                    foreach ($this->parameterFilter as $filterName => $filter) {
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
                        if (!empty($filter->sumas->{$sumaName})) {
    
                            $validTmp = true;
                            break;
                        }
                    }
                    if (!$validTmp) {
                        $valid = false;
                    }
                }
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
    
                # If the suma is still valid, we can add it
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
                    $this->enabledSearchengines[$sumaName] = $suma;
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            if (!empty($timings)) {
                $timings["createSearchEngines"]["filtered invalid engines"] = microtime(true) - $timings["starttime"];
            }
    
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
            # Include Yahoo Ads if Yahoo is not enabled as a searchengine
            if (!$this->apiAuthorized && $this->fokus != "bilder" && empty($this->enabledSearchengines["yahoo"]) && isset($this->sumaFile->sumas->{"yahoo-ads"})) {
    
                $this->enabledSearchengines["yahoo-ads"] = $this->sumaFile->sumas->{"yahoo-ads"};
            }
    
    
            # Special case if search engines are disabled
            # Since bing is normally only active if a filter is set but it should be active, too if yahoo is disabled
            if ($this->getFokus() === "web" && empty($this->enabledSearchengines["yahoo"]) && \Cookie::get("web_engine_bing") !== "off") {
                $this->enabledSearchengines["bing"] = $this->sumaFile->sumas->{"bing"};
            }
    
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            if (sizeof($this->enabledSearchengines) === 0) {
    
                $filter = "";
                foreach ($this->queryFilter as $queryFilter => $filterPhrase) {
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
                    $filter .= trans($this->sumaFile->filter->{"query-filter"}->{$queryFilter}->name) . ",";
    
                }
                $filter = rtrim($filter, ",");
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
                $error = trans('metaGer.engines.noSpecialSearch', [
                    'fokus' => trans($this->sumaFile->foki->{$this->fokus}->{"display-name"}),
    
                    'filter' => $filter,
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
                ]);
    
                $this->errors[] = $error;
    
            $this->setEngines($request);
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            if (!empty($timings)) {
                $timings["createSearchEngines"]["saved engines"] = microtime(true) - $timings["starttime"];
            }
    
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
        private function removeAdsFromListIfAdfree(&$sumas)
        {
            if ($this->apiAuthorized) {
                foreach ($sumas as $sumaName => $suma) {
                    $ads = $suma->ads ?? false;
                    if ($ads) {
                        unset($sumas[$sumaName]);
    
                        $adBackups = $suma->{"ad-backups"} ?? [];
                        $adBackupName = $adBackups->{$this->fokus} ?? null;
                        if (isset($adBackupName)) {
                            $this->sumaFile->sumas->{$adBackupName}->{"filter-opt-in"} = false;
                        }
                    }
                }
            }
        }
    
    
        public function setEngines(Request $request, $enabledSearchengines = [])
        {
    
            if ($this->requestIsCached($request)) {
    
                # If this is a page other than 1 the request is "cached"
    
                $engines = $this->getCachedEngines($request);
    
                # We need to edit some Options of the Cached Search Engines
    
                foreach ($engines as $engine) {
    
                    $engine->setResultHash($this->getSearchUid());
    
                $this->engines = $engines;
    
                if (sizeof($enabledSearchengines) > 0) {
                    $this->enabledSearchengines = $enabledSearchengines;
                }
    
                $this->actuallyCreateSearchEngines($this->enabledSearchengines);
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
        public function startSearch(&$timings)
    
            if (!empty($timings)) {
                $timings["startSearch"]["start"] = microtime(true) - $timings["starttime"];
            }
    
            # Check all engines for Cached responses
            if ($this->canCache()) {
                $keys = [];
                foreach ($this->engines as $engine) {
                    $keys[] = $engine->hash;
                }
                $cacheValues = Cache::many($keys);
                foreach ($this->engines as $engine) {
                    if ($cacheValues[$engine->hash] !== null) {
                        $engine->cached = true;
                        $engine->retrieveResults($this, $cacheValues[$engine->hash]);
                    }
                }
            }
            if (!empty($timings)) {
                $timings["startSearch"]["cache checked"] = microtime(true) - $timings["starttime"];
            }
    
    
            foreach ($this->engines as $engine) {
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
                $engine->startSearch($this, $timings);
    
            if (!empty($timings)) {
                $timings["startSearch"]["searches started"] = microtime(true) - $timings["starttime"];
            }
    
    
        public function sumaIsSelected($suma, $request, $custom)
    
                if ($request->filled("engine_" . strtolower($suma["name"]))) {
    
                    return true;
                }
            } else {
                $types = explode(",", $suma["type"]);
                if (in_array($this->fokus, $types)) {
                    return true;
                }
            }
            return false;
        }
    
    
        public function actuallyCreateSearchEngines($enabledSearchengines)
    
            foreach ($enabledSearchengines as $engineName => $engine) {
    
                if (!isset($engine->{"parser-class"})) {
    
                    die(var_dump($engine));
                }
    
                $path = "App\\Models\\parserSkripte\\" . $engine->{"parser-class"};
    
                if (!file_exists(app_path() . "/Models/parserSkripte/" . $engine->{"parser-class"} . ".php")) {
                    Log::error("Konnte " . $engine->{"display-name"} . " nicht abfragen, da kein Parser existiert");
                    $this->errors[] = trans('metaGer.engines.noParser', ['engine' => $engine->{"display-name"}]);
    
                    continue;
                }
    
                # Es wird versucht die Suchengine zu erstellen
                $time = microtime();
                try {
    
                    $tmp = new $path($engineName, $engine, $this);
    
                    Log::error("Konnte " . $engine->{"display-name"} . " nicht abfragen. " . $e);
    
            $this->engines = $engines;
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
        public function getAvailableParameterFilter()
        {
            $parameterFilter = $this->sumaFile->filter->{"parameter-filter"};
    
            $availableFilter = [];
    
            foreach ($parameterFilter as $filterName => $filter) {
    
                $values = clone $filter->values;
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
                # Check if any of the enabled search engines provide this filter
                foreach ($this->enabledSearchengines as $engineName => $engine) {
                    if (!empty($filter->sumas->$engineName)) {
    
                        if (empty($availableFilter[$filterName])) {
                            $availableFilter[$filterName] = $filter;
    
                            foreach($availableFilter[$filterName]->values as $key => $value){
                                if($key !== "nofilter"){
                                    unset($availableFilter[$filterName]->values->{$key});
                                }
                            }
    
                        }
                        if (empty($availableFilter[$filterName]->values)) {
    
                            $availableFilter[$filterName]->values = new \stdClass();
    
                        }
                        foreach ($filter->sumas->{$engineName}->values as $key => $value) {
    
                            $availableFilter[$filterName]->values->{$key} = $values->$key;
    
                # We will also add the filter from the opt-in search engines (the searchengines that are only used when a filter of it is too)
                foreach ($this->sumaFile->foki->{$this->fokus}->sumas as $suma) {
    
                    if ($this->sumaFile->sumas->{$suma}->{"filter-opt-in"} && \Cookie::get($this->getFokus() . "_engine_" . $suma) !== "off") {
    
                        if (!empty($filter->sumas->{$suma})) {
    
                            # If the searchengine is disabled this filter shouldn't be available
                            if ((!empty($this->sumaFile->sumas->{$suma}->disabled) && $this->sumaFile->sumas->{$suma}->disabled === true)
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
                                || (!empty($this->sumaFile->sumas->{$suma}->{"auto-disabled"}) && $this->sumaFile->sumas->{$suma}->{"auto-disabled"} === true)
                            ) {
    
                            if (empty($availableFilter[$filterName])) {
                                $availableFilter[$filterName] = $filter;
    
                                foreach($availableFilter[$filterName]->values as $key => $value){
                                    if($key !== "nofilter"){
                                        unset($availableFilter[$filterName]->values->{$key});
                                    }
                                }
    
                            }
                            if (empty($availableFilter[$filterName]->values)) {
    
                                $availableFilter[$filterName]->values = new \stdClass();
    
                            }
                            foreach ($filter->sumas->{$suma}->values as $key => $value) {
    
                                $availableFilter[$filterName]->values->{$key} = $values->$key;
    
            # Set the current values for the filters
            foreach ($availableFilter as $filterName => $filter) {
                if (\Request::filled($filter->{"get-parameter"})) {
                    $filter->value = \Request::input($filter->{"get-parameter"});
                } else if (\Cookie::get($this->getFokus() . "_setting_" . $filter->{"get-parameter"}) !== null) {
                    $filter->value = \Cookie::get($this->getFokus() . "_setting_" . $filter->{"get-parameter"});
                }
            }
    
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            return $availableFilter;
        }
    
    
            return $this->fokus === "bilder";
    
        }
    
        public function sumaIsAdsuche($suma, $overtureEnabled)
        {
    
            $sumaName = $suma["name"]->__toString();
    
                $sumaName === "qualigo"
                || $sumaName === "similar_product_ads"
    
                || (!$overtureEnabled && $sumaName === "overtureAds");
    
            isset($suma['disabled'])
            && $suma['disabled']->__toString() === "1";
    
            $suma["name"]->__toString() === "overture"
            || $suma["name"]->__toString() === "overtureAds";
    
        }
    
        public function sumaIsNotAdsuche($suma)
        {
            return
    
            $suma["name"]->__toString() !== "qualigo"
            && $suma["name"]->__toString() !== "similar_product_ads"
            && $suma["name"]->__toString() !== "overtureAds";
    
        }
    
        public function requestIsCached($request)
        {
            return
    
            $request->filled('next')
            && Cache::has($request->input('next'))
            && unserialize(Cache::get($request->input('next')))['page'] > 1;
    
        }
    
        public function getCachedEngines($request)
        {
    
            $next = unserialize(Cache::get($request->input('next')));
    
        public function waitForMainResults()
    
            $engines = $this->engines;
    
            $enginesToWaitFor = [];
    
            $mainEngines = $this->sumaFile->foki->{$this->fokus}->main;
            foreach ($mainEngines as $mainEngine) {
                foreach ($engines as $engine) {
    
                    if ($engine->name === $mainEngine && !$engine->loaded) {
    
                        $enginesToWaitFor[] = $engine;
                    }
    
            $timeStart = microtime(true);
    
    
            # If there is no main searchengine to wait for or if the only main engine is yahoo-ads we will define a timeout of 1s
            $forceTimeout = null;
    
            if (sizeof($enginesToWaitFor) === 1 && $enginesToWaitFor[0]->name === "yahoo-ads") {
    
                $forceTimeout = 1;
            }
    
            while (sizeof($enginesToWaitFor) > 0 || ($forceTimeout !== null && (microtime(true) - $timeStart) < $forceTimeout)) {
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
                foreach ($enginesToWaitFor as $index => $engine) {
    
                    if (Redis::get($engine->hash) !== null) {
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
                        $answered[] = $engine;
                        unset($enginesToWaitFor[$index]);
                        break;
    
                if ((microtime(true) - $timeStart) >= 2) {
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
                } else {
                    usleep(50 * 1000);
    
        public function retrieveResults()
    
            $engines = $this->engines;
    
            # Von geladenen Engines die Ergebnisse holen
    
            foreach ($engines as $engine) {
                if (!$engine->loaded) {
                    try {
    
                        $engine->retrieveResults($this);
    
                if (!empty($engine->totalResults) && $engine->totalResults > $this->totalResults) {
                    $this->totalResults = $engine->totalResults;
                }
    
                if (!empty($engine->alteredQuery) && !empty($engine->alterationOverrideQuery)) {
                    $this->alteredQuery = $engine->alteredQuery;
                    $this->alterationOverrideQuery = $engine->alterationOverrideQuery;
                }
    
    Karl Hasselbring's avatar
    Karl Hasselbring committed
        /*
    
         * Ende Suchmaschinenerstellung und Ergebniserhalt
         */
    
    Karl's avatar
    Karl committed
    
    
        public function parseFormData(Request $request)
        {
    
            # Sichert, dass der request in UTF-8 formatiert ist
    
            if ($request->input('encoding', 'utf8') !== "utf8") {
    
                # In früheren Versionen, als es den Encoding Parameter noch nicht gab, wurden die Daten in ISO-8859-1 übertragen
                $input = $request->all();
                foreach ($input as $key => $value) {
                    $input[$key] = mb_convert_encoding("$value", "UTF-8", "ISO-8859-1");
                }
                $request->replace($input);
            }
    
            $this->fullUrl = $request->fullUrl();
    
            # Zunächst überprüfen wir die eingegebenen Einstellungen:
    
            $this->fokus = $request->input('focus', 'web');
    
                $this->sumaFile = config_path() . "/sumasEn.json";
    
                $this->sumaFile = config_path() . "/sumas.json";
    
            if (!file_exists($this->sumaFile)) {
    
            } else {
                $this->sumaFile = json_decode(file_get_contents($this->sumaFile));
    
            $this->eingabe = trim($request->input('eingabe', ''));
    
            $this->ip = $this->anonymizeIp($request->ip());
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            $this->useragent = $request->header('User-Agent');
    
    
            if (isset($_SERVER['HTTP_LANGUAGE'])) {
    
                $this->language = $_SERVER['HTTP_LANGUAGE'];
    
            $this->page = 1;
    
            # Lang
            $this->lang = $request->input('lang', 'all');
    
            if ($this->lang !== "de" && $this->lang !== "en" && $this->lang !== "all") {
                $this->lang = "all";
    
            $this->mobile = $this->agent->isMobile();
    
            if (!App::isLocale("de") || (\Cookie::has($this->getFokus() . '_setting_zitate') && \Cookie::get($this->getFokus() . '_setting_zitate') === "off")) {
    
                $this->sprueche = "off";
            }else{
                $this->sprueche = "on";
            }
    
            if($request->filled("zitate") && $request->input('zitate') === "on" || $request->input('zitate') === "off"){
    
                $this->sprueche = $request->input('quotes');
    
            $this->newtab = $request->input('newtab', 'on');
    
            if ($this->newtab === "on") {
                $this->newtab = "_blank";
            } else {
                $this->newtab = "_self";
            }
    
            if ($request->filled("key") && $request->input('key') === getenv("mainz_key")) {
    
                $this->newtab = "_blank";
    
            $this->theme = preg_replace("/[^[:alnum:][:space:]]/u", '', $request->input('theme', 'default'));
    
            # Ergebnisse pro Seite:
            $this->resultCount = $request->input('resultCount', '20');
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            if ($request->filled('minism') && ($request->filled('fportal') || $request->filled('harvest'))) {
    
                $newInput = [];
                foreach ($input as $key => $value) {
                    if ($key !== "fportal" && $key !== "harvest") {
                        $newInput[$key] = $value;
                    }
                }
                $request->replace($newInput);
    
            if ($this->resultCount <= 0 || $this->resultCount > 200) {
                $this->resultCount = 1000;
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            if ($request->filled('onenewspageAll') || $request->filled('onenewspageGermanyAll')) {
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            if ($request->filled('password')) {
    
                $this->password = $request->input('password');
    
    Dominik Hebeler's avatar
    Dominik Hebeler committed
            if ($request->filled('quicktips')) {