MetaGerSearch.php 8.05 KB
Newer Older
Dominik Hebeler's avatar
Dominik Hebeler committed
1
2
3
4
<?php

namespace App\Http\Controllers;

5
use App;
6
use App\MetaGer;
7
use Cache;
8
use Illuminate\Http\Request;
9
use Illuminate\Support\Facades\Redis;
10
use LaravelLocalization;
11
use View;
Dominik Hebeler's avatar
Dominik Hebeler committed
12

13
const TIP_SERVER = 'http://metager3.de:63825/tips.xml';
14

Dominik Hebeler's avatar
Dominik Hebeler committed
15
16
class MetaGerSearch extends Controller
{
17
    public function search(Request $request, MetaGer $metager)
18
    {
19
        $focus = $request->input("focus", "web");
20

21
22
23
24
25
        if ($focus === "maps") {
            $searchinput = $request->input('eingabe', '');
            return redirect()->to('https://maps.metager.de/map/' . $searchinput . '/1240908.5493525574,6638783.2192695495,6');
        }

26
27
28
29
30
31
        # If there is no query parameter we redirect to the startpage
        $eingabe = $request->input('eingabe', '');
        if (empty(trim($eingabe))) {
            return redirect(LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), '/'));
        }

32
33
        # Mit gelieferte Formulardaten parsen und abspeichern:
        $metager->parseFormData($request);
34

35
36
        # Nach Spezialsuchen überprüfen:
        $metager->checkSpecialSearches($request);
37

38
39
40
        # Die Quicktips als Job erstellen
        $quicktips = $metager->createQuicktips();

41
        # Suche für alle zu verwendenden Suchmaschinen als Job erstellen,
42
        # auf Ergebnisse warten und die Ergebnisse laden
43
        $metager->createSearchEngines($request);
44

45
46
47
48
49
50
        $metager->startSearch();

        $metager->waitForMainResults();

        $metager->retrieveResults();

51
52
        # Versuchen die Ergebnisse der Quicktips zu laden
        $quicktipResults = $quicktips->loadResults();
53
54
55
        # Alle Ergebnisse vor der Zusammenführung ranken:
        $metager->rankAll();

56
        # Ergebnisse der Suchmaschinen kombinieren:
Phil Höfer's avatar
Phil Höfer committed
57
        $metager->prepareResults();
58

59
60
61
62
63
64
        # Save the results in Redis
        $redis = Redis::connection(env('REDIS_RESULT_CONNECTION'));
        $pipeline = $redis->pipeline();
        foreach ($metager->getResults() as $result) {
            $pipeline->rpush($metager->getRedisCurrentResultList(), base64_encode(serialize($result)));
        }
65
        $pipeline->expire($metager->getRedisCurrentResultList(), env('REDIS_RESULT_CACHE_DURATION'));
66
67
        $pipeline->execute();

68
        # Die Ausgabe erstellen:
69
        return $metager->createView($quicktipResults);
Dominik Hebeler's avatar
Dominik Hebeler committed
70
71
    }

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
    public function loadMore(Request $request)
    {
        /**
         * There are three forms of requests to the resultpage
         * 1. Initial Request: Loads the fastest searchengines and sends them to the user
         * 2. Load more results (with JS): Loads new search engines that answered after the initial request was send
         * 3. Load more results (without JS): Loads new search engines that answered within 1s timeout
         */
        if ($request->filled('loadMore') && $request->filled('script') && $request->input('script') === "yes") {
            return $this->loadMoreJS($request);
        }

    }

    private function loadMoreJS(Request $request)
    {
        # Create a MetaGer Instance with the supplied hash
        $hash = $request->input('loadMore', '');

        $metager = new MetaGer($hash);
        $redis = Redis::connection(env('REDIS_RESULT_CONNECTION'));

        $result = [];
        # Check if there should be more results
        $stats = $redis->hgetall($metager->getRedisEngineResult() . "status");
        $stats["startTime"] = floatval($stats["startTime"]);
        $stats["engineCount"] = intval($stats["engineCount"]);
        $stats["engineAnswered"] = intval($stats["engineAnswered"]);
        $stats["engineDelivered"] = intval($stats["engineDelivered"]);

        $result["finished"] = true;
        $result["engineCount"] = $stats["engineCount"];
        $result["engineAnswered"] = $stats["engineAnswered"];
        $result["engineDelivered"] = $stats["engineDelivered"];
        $result["timeWaiting"] = microtime(true) - $stats["startTime"];

        # Check if we can abort
        if ($stats["engineAnswered"] > $stats["engineDelivered"]/*&& $result["timeWaiting"] <= 10 */) {
            $metager->parseFormData($request);
            # Nach Spezialsuchen überprüfen:
            $metager->checkSpecialSearches($request);

            # Read which search engines are new
            $newEngines = [];

117
            while (($engine = $redis->lpop($metager->getRedisResultWaitingKey())) != null) {
118
119
120
                $result["engineDelivered"]++;
                $newEngines[$engine] = $metager->getSumaFile()->sumas->{$engine};
            }
121
122
123
124
125
126
127
128
129
            $cache = Cache::get($hash);
            if ($cache != null) {
                $metager->setNext(unserialize($cache)["engines"]);
            }

            # Check if this request is not for page one
            $metager->setEngines($request, $newEngines);

            # Add the results already delivered to the user
130
131
132
133
134
135
136
137
138
            $results = $redis->lrange($metager->getRedisCurrentResultList(), 0, -1);
            foreach ($results as $index => $oldResult) {
                $results[$index] = unserialize(base64_decode($oldResult));
                $results[$index]->new = false;
            }
            $metager->setResults($results);
            $metager->retrieveResults();
            $metager->rankAll();
            $metager->prepareResults();
139
            $result["nextSearchLink"] = $metager->nextSearchLink();
140
141
142
            $results = $metager->getResults();
            foreach ($results as $index => $resultTmp) {
                if ($resultTmp->new) {
143
144
145
146
147
148
149
150
151
152
153
                    if ($metager->getFokus() !== "bilder") {
                        $view = View::make('layouts.result', ['result' => $resultTmp, 'metager' => $metager]);
                        $html = $view->render();
                        $result['newResults'][$index] = $html;
                        $result["imagesearch"] = false;
                    } else {
                        $view = View::make('layouts.image_result', ['result' => $resultTmp, 'metager' => $metager]);
                        $html = $view->render();
                        $result['newResults'][$index] = $html;
                        $result["imagesearch"] = true;
                    }
154
155
                }
            }
156
157
158
159
160
161
162
163
            # Save the results in Redis
            $pipeline = $redis->pipeline();
            $pipeline->hincrby($metager->getRedisEngineResult() . "status", "engineDelivered", sizeof($newEngines));
            $pipeline->hset($metager->getRedisEngineResult() . "status", "nextSearchLink", $result["nextSearchLink"]);
            foreach ($metager->getResults() as $resultTmp) {
                $resultTmp->new = false;
                $pipeline->rpush($metager->getRedisCurrentResultList(), base64_encode(serialize($resultTmp)));
            }
164
            $pipeline->expire($metager->getRedisCurrentResultList(), env('REDIS_RESULT_CACHE_DURATION'));
165
            $pipeline->execute();
166
167
168
169
170

        }
        return response()->json($result);
    }

171
172
173
174
175
176
177
178
    public function botProtection($redirect)
    {
        $hash = md5(date('YmdHi'));
        return view('botProtection')
            ->with('hash', $hash)
            ->with('r', $redirect);
    }

179
180
    public function get($url)
    {
181
        $ctx = stream_context_create(array('http' => array('timeout' => 2)));
182
        return file_get_contents($url, false, $ctx);
183
    }
184
185
186
187
188
189

    private function startsWith($haystack, $needle)
    {
        $length = strlen($needle);
        return (substr($haystack, 0, $length) === $needle);
    }
190
191
192
193

    public function tips(Request $request)
    {
        $tips_text = file_get_contents(TIP_SERVER);
194
        $tips = [];
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
        try {
            $tips_xml = simplexml_load_string($tips_text);

            $tips_xml->registerXPathNamespace('mg', 'http://metager.de/tips/');
            $tips_xml = $tips_xml->xpath('mg:tip');
            foreach ($tips_xml as $tip_xml) {
                $tips[] = $tip_xml->__toString();
            }
        } catch (\Exception $e) {
            Log::error("A problem occurred loading tips from the tip server.");
            Log::error($e->getMessage());
            abort(500);
        }
        return view('tips')
            ->with('title', trans('tips.title'))
            ->with('tips', $tips);
    }
212
}