MetaGer.php 35.1 KB
Newer Older
1
2
3
4
5
6
<?php
namespace App;

use Illuminate\Http\Request;
use Jenssegers\Agent\Agent;
use App;
7
8
use Storage;
use Log;
9
use Config;
10
use Redis;
11
12
13
14
use App\lib\TextLanguageDetect\TextLanguageDetect;
use App\lib\TextLanguageDetect\LanguageDetect\TextLanguageDetectException;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
15

16
17
18
19
/**
*  Dies ist die Hauptklasse für jede Suche. 
*  Sie sammelt alle Ein- und Ausgaben und verarbeitet diese.
*/
20
21
class MetaGer
{
22
23
24
25
26
27
28
29
30
31
	/* Noch nicht hier oben: (unter anderem)
	*  url 				-	???
	*  language			-	???
	*  category			-	???
	*  tab				-	gewählter Ergebnistab
	*  password			-	???
	*  quicktips		-	Quicktips ein-/ausgeschaltet
	*  out				-	???
	*  request			-	Sicherung der Anfrage
	*/
32
	# Einstellungen für die Suche
33
	protected $fokus;						# Der gewählte Suchfokus
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
	protected $eingabe;						# Die eingegebenen Suchbegriffe
	protected $q;							# Die eingegebenen Suchbegriffe ???
	protected $category;					# 
	protected $time;						# Die maximale Suchzeit
	protected $page;						# Die ausgewählte Ergebnisseite
	protected $lang;						# Die gewählte Sprache der Suchergebnisse
	protected $cache = "";					# 
	protected $site;						# Erkannte Sitesearches
	protected $hostBlacklist = [];			# Die Blacklist der Hosts
	protected $domainBlacklist = [];		# Die Blacklist der Domains
	protected $stopWords = [];				# Erkannte Stopworte
	protected $phrases = [];				# Erkannte Phrasensuchen
	protected $engines = [];				# 
	protected $results = [];				# Die gesammelten Ergebnisse
	protected $ads = [];					# Die gesammelten Werbungen
	protected $warnings = [];				# Die entstandenen Warnmeldungen
	protected $errors = [];					# Die entstandenen Fehlermeldungen
	protected $addedHosts = [];				# 
	# Daten über die Abfrage
	protected $ip;							# Die IP des Nutzers
	protected $language;					# 
	protected $agent;						# Ein Agent - unter anderem zur Browser-, Sprach- und Mobilgeräteerkennung
	# Konfigurationseinstellungen:
	protected $sumaFile;					# Die Suma-Datei je nach Sprache
	protected $mobile;						# Nutzer auf Mobilgerät
	protected $resultCount;					# Gewünschte Anzahl Ergebnisse pro Seite
	protected $sprueche;					# Sprüche ein-/ausgeschaltet
61
62
63
64
65
	protected $domainsBlacklisted = [];		#
	protected $urlsBlacklisted = [];		#
	protected $url;							#
	protected $languageDetect;				#

66
	# Erstellt einen noch leeren MetaGer. Dabei werden erst einmal nur die Blacklists für Domains und URLs geladen und die Spracherkennung festgelegt.
67
68
	function __construct()
	{
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
		$this->starttime = microtime(true);   
		if( file_exists(config_path() . "/blacklistDomains.txt") && file_exists(config_path() . "/blacklistUrl.txt") )
		{
			# Blacklists einlesen:
			$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);
		}else
		{
			Log::warning("Achtung: Eine, oder mehrere Blacklist Dateien, konnten nicht geöffnet werden");
		}

		$this->languageDetect = new TextLanguageDetect();
		$this->languageDetect->setNameMode("2");
84
85
	}

86
87
88
89
90
91
92
93
	# Ruft für jede Engine eine Ranking-Funktion auf. Diese ruft dann wiederum eine Ranking-Funktion für jedes Ergebnis auf, mit der sich die Ergebnisse selbst ranken.
	public function rankAll ()
	{
		foreach( $this->engines as $engine )
		{
			$engine->rank($this);
		}
	}
94

95
	# Ruft abhängig vom Suchfokus und vom Ausgabetyp verschiedene Views auf, mit denen die Suchergebnisse dargestellt werden.
96
97
98
	public function createView()
	{
		$viewResults = [];
99

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
		# 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();

		# Falls der Suchfokus Bilder ist.
		if( $this->fokus === "bilder" ) {
			switch ($this->out) {
				case 'results':
					return view('metager3bilderresults')
						->with('results', $viewResults)
						->with('eingabe', $this->eingabe)
						->with('mobile', $this->mobile)
						->with('warnings', $this->warnings)
						->with('errors', $this->errors)
						->with('metager', $this);
120
                        ->with('browser', (new Agent())->browser());
121
122
123
124
125
126
127
128
129
					break;
				default:
					return view('metager3bilder')
						->with('results', $viewResults)
						->with('eingabe', $this->eingabe)
						->with('mobile', $this->mobile)
						->with('warnings', $this->warnings)
						->with('errors', $this->errors)
						->with('metager', $this);
130
                        ->with('browser', (new Agent())->browser());
131
132
133
					break;
			}
		# Falls der Suchfokus nicht Bilder ist.
134
135
		}else 
		{
136
137
138
139
140
141
142
143
144
			switch ($this->out) {
				case 'results':
					return view('metager3results')
						->with('results', $viewResults)
						->with('eingabe', $this->eingabe)
						->with('mobile', $this->mobile)
						->with('warnings', $this->warnings)
						->with('errors', $this->errors)
						->with('metager', $this);
145
                    ->with('browser', (new Agent())->browser());
146
147
148
149
150
151
152
153
154
155
					break;
				case 'results-with-style':
					return view('metager3')
						->with('results', $viewResults)
						->with('eingabe', $this->eingabe)
						->with('mobile', $this->mobile)
						->with('warnings', $this->warnings)
						->with('errors', $this->errors)
						->with('metager', $this)
						->with('suspendheader', "yes");
156
                    ->with('browser', (new Agent())->browser());
157
158
159
160
161
162
163
164
					break;
				default:
					return view('metager3')
						->with('eingabe', $this->eingabe)
						->with('mobile', $this->mobile)
						->with('warnings', $this->warnings)
						->with('errors', $this->errors)
						->with('metager', $this);
165
                    ->with('browser', (new Agent())->browser());
166
167
168
					break;
			}
		}
169
170
	}

171
	# Erstellt für die aktuelle Suche einen Log auf dem Redis-Server
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
	private function createLogs()
	{
		$redis = Redis::connection('redisLogs');
		try
		{
			$logEntry = "";
			$logEntry .= "[" . date(DATE_RFC822, mktime(date("H"),date("i"), date("s"), date("m"), date("d"), date("Y"))) . "]";
			$logEntry .= " From=" . $this->ip;
			$logEntry .= " pid=" . getmypid();
			$anonId= md5("MySeCrEtSeEdFoRmd5"
			.$this->request->header('Accept')
			.$this->request->header('Accept-Charset')
			.$this->request->header('Accept-Encoding')
			.$this->request->header('HTTP_LANGUAGE')
			.$this->request->header('User-Agent')
			.$this->request->header('Keep-Alive')
			.$this->request->header('X-Forwarded-For')
			.date("H")); # Wichtig!! Den Parameter um die aktuelle Stunde erweitern. Ansonsten wäre die anonId dauerhaft einem Nutzer zuzuordnen.
			$logEntry .= " anonId=$anonId";
			$logEntry .= " ref=" . $this->request->header('Referer');
			$useragent = $this->request->header('User-Agent');
			$useragent = str_replace("(", " ", $useragent);
			$useragent = str_replace(")", " ", $useragent);
			$useragent = str_replace(" ", "", $useragent);
			$logEntry .= " ua=" . $useragent;
			$logEntry .= " iter= mm= time=" . round((microtime(true)-$this->starttime), 2) . " serv=" . $this->fokus . " which= hits= stringSearch= QuickTips= SSS= check=";
			$logEntry .= " search=" . $this->eingabe;
			$redis->rpush('logs.search', $logEntry);
		}catch( \Exception $e)
		{
			return;
		}
	}

206
	# Entfernt alle nicht gültigen Ergebnisse aus der Ergebnisliste
207
208
209
210
211
212
213
214
215
	public function removeInvalids ()
	{
		$results = [];
		foreach($this->results as $result)
		{
			if($result->isValid($this))
				$results[] = $result;
		}
	}
216

217
	# 
218
219
	public function combineResults ()
	{
220
		# sammelt die gültigen Ergebnisse und ads aller Suchmaschinen in der results-Liste
221
222
		foreach($this->engines as $engine)
		{
223
224
225
226
227
228
229
230
231
232
			foreach($engine->results as $result)
			{
				if($result->valid)
					$this->results[] = $result;
			}
			foreach($engine->ads as $ad)
			{
				$this->ads[] = $ad;
			}
		}
233
234

		# Sortiert die Ergebnisse nach Ranking
235
236
237
238
239
		uasort($this->results, function($a, $b){
			if($a->getRank() == $b->getRank())
				return 0;
			return ($a->getRank() < $b->getRank()) ? 1 : -1;
		});
240
241
242

		# Überprüft alle Ergebnisse auf Gültigkeit
		# Kann das weg? Wird oben auch gemacht ???
243
244
245
246
247
248
249
250
		$newResults = [];
		foreach($this->results as $result)
		{
			if($result->isValid($this))
				$newResults[] = $result;
		}
		$this->results = $newResults;

251
		# Teilt den Ergebnisse nach Ranking ihre Position sowie eine Farbe zu. Die Farbe gibt auskunft, wie viel "schlechter" das Ergebnis im Vergleich zum besten Ergebnis ist.
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
		$counter = 0;
		$firstRank = 0;
		foreach($this->results as $result)
		{
			if($counter === 0)
				$firstRank = $result->rank;
			$counter++;
			$result->number = $counter;
			$confidence = 0;
			if($firstRank > 0)
				$confidence = $result->rank/$firstRank;
			else
				$confidence = 0;
			if($confidence > 0.65)
				$result->color = "#FF4000";
			elseif($confidence > 0.4)
				$result->color = "#FF0080";
			elseif($confidence > 0.2)
				$result->color = "#C000C0";
			else
				$result->color = "#000000";
		}

275
		# Liest die derzeitige Seite und den zugehörigen Offset aus der URL: ...&page=6
276
		$currentPage = LengthAwarePaginator::resolveCurrentPage();
277
		$offset = $currentPage-1;
278

279
		# Erstellt eine neue Laravel-Collection aus der Ergebnisliste
280
281
		$collection = new Collection($this->results);

282
		# Legt die angezeigten Ergebnisse pro Seite fest
283
284
		$perPage = $this->resultCount;

285
		# Extrahiert mit Offset und Ergebnisse pro Seite die anzuzeugenden Ergebnisse aus der Ergebnis-Collection
286
287
288
289
290
		$currentPageSearchResults = $collection->slice($offset * $perPage, $perPage)->all();

		# Für diese 20 Links folgt nun unsere Boost-Implementation.
		$currentPageSearchResults = $this->parseBoost($currentPageSearchResults);

291
		# Für diese 20 Links folgt nun unsere Adgoal-Implementation.
292
293
		$currentPageSearchResults = $this->parseAdgoal($currentPageSearchResults);

294
		// Create our paginator and pass it to the view ???
295
296
297
298
299
300
301
302
303
304
305
		$paginatedSearchResults= new LengthAwarePaginator($currentPageSearchResults, count($collection), $perPage);
		$paginatedSearchResults->setPath('/meta/meta.ger3');
		foreach($this->request->all() as $key => $value)
		{
			if( $key === "out" )
				continue;
			$paginatedSearchResults->addQuery($key, $value);
		}

		$this->results = $paginatedSearchResults;
		$this->validated = false;
306
307

		# Wir bieten einen bezahlten API-Zugriff an, bei dem dementsprechend die Werbung ausgeblendet wurde. Aktuell ist es nur die Uni-Mainz. Deshalb überprüfen wir auch nur diese.
308
309
310
311
312
313
314
315
316
317
		if( isset($this->password) )
		{
			$password = getenv('mainz');
			$eingabe = $this->eingabe;
			$password = md5($eingabe . $password);
			if( $this->password === $password )
			{
				$this->ads = [];
				$this->validated = true;
			}
318
319
320
		}
	}

321
	# Fügt beim Boost-Partnershop Amazon dem Link unser boost-tag an
322
323
	public function parseBoost($results)
	{
Phil Höfer's avatar
Phil Höfer committed
324
	foreach($results as $result)
325
		{
Phil Höfer's avatar
Phil Höfer committed
326
327
328
		if(preg_match('/^(http[s]?\:\/\/)?(www.)?amazon\.de/',$result->anzeigeLink))
		{
			if(preg_match('/\?/',$result->anzeigeLink))
329
					{
Phil Höfer's avatar
Phil Höfer committed
330
				$result->link .= '&tag=boostmg01-21';
331
					} else
Phil Höfer's avatar
Phil Höfer committed
332
333
334
335
336
337
338
339
			{
				$result->link .= '?tag=boostmg01-21';
			}
			$result->partnershop = true;

		}
	}	
	return $results;
340
	}
341
342

	# ???
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
	public function parseAdgoal($results)
	{
		$publicKey = getenv('adgoal_public');
		$privateKey = getenv('adgoal_private');
		if( $publicKey === FALSE )
		{
			return $results;
		}
		$tldList = "";
		try{
			foreach($results as $result)
			{
				$link = $result->anzeigeLink;
				if(strpos($link, "http") !== 0)
				{
					$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 
			$query = urlencode($this->q);

			$link = "https://api.smartredirect.de/api_v2/CheckForAffiliateUniversalsearchMetager.php?p=" . $publicKey . "&k=" . $hash . "&tld=" . $tldList . "&q=" . $query; 
			$answer = json_decode(file_get_contents($link));


			# Nun müssen wir nur noch die Links für die Advertiser ändern:
			foreach($answer as $el)
			{
				$hoster = $el[0];
				$hash = $el[1];

				foreach($results as $result)
				{
					if( $hoster === $result->tld )
					{
						# Hier ist ein Advertiser:
						# Das Logo hinzufügen:
						$result->image = "https://img.smartredirect.de/logos_v2/120x60/" . $hash . ".gif";
						# Den Link hinzufügen:
						$publicKey = $publicKey;
						$targetUrl = $result->anzeigeLink;
						if(strpos($targetUrl, "http") !== 0)
							$targetUrl = "http://" . $targetUrl;
393
394
                        $gateHash = md5($targetUrl . $privateKey);
                        $newLink = "https://api.smartredirect.de/api_v2/ClickGate.php?p=" . $publicKey . "&k=" . $gateHash . "&url=" . urlencode($targetUrl) . "&q=" . $query;
395
396
397
398
399
400
401
402
403
404
405
406
						$result->link = $newLink;
						$result->partnershop = true;
					}
				}
			}
		}catch(\ErrorException $e)
		{
			return $results;
		}

		return $results;
	}
Dominik Hebeler's avatar
Dominik Hebeler committed
407

408
409
	# Erstellt aus den Suchparametern des Nutzers die Suchengines.
	# Diese laufen dann über einen Redis-Server. ???
410
411
	public function createSearchEngines (Request $request)
	{
412
		# Keine Suchwörter eingegeben
413
414
		if( !$request->has("eingabe") )
			return;
415

416
417
418
419
420
		$xml = simplexml_load_file($this->sumaFile);
		$enabledSearchengines = [];
		$overtureEnabled = FALSE;
		$countSumas = 0;
		$sumas = $xml->xpath("suma");
421
		
422
		# Die beiden if-Teile überschneiden sich stark. ??? zusammenführen ???
423
		# Überprüfe, welche Sumas eingeschaltet sind
424
425
426
427
		if($this->fokus === "angepasst")
		{
			foreach($sumas as $suma)
			{
428
429
430
431
432
433
434
435
436
437
438
				/* Prüft ob die Suma explizit eingeschaltet oder eine Werbe-Suma ist
				*  (Die Suma steht in der Anfrage) oder 
				*  (	(Der Suchfokus ist nicht Bilder) und 
				* 		(	(Es ist Qualigo) oder 
				* 			(Es ist Similar Product Ads) oder 
				* 			(	(Overture ist nicht eingeschaltet) und 
				* 				(Es ist Overture Ads)
				* 			)
				* 		)
				* 	)
				*/
439
440
441
442
443
444
445
446
447
				if($request->has($suma["name"]) 
					|| ( $this->fokus !== "bilder" 
						&& ($suma["name"]->__toString() === "qualigo" 
							|| $suma["name"]->__toString() === "similar_product_ads" 
							|| ( !$overtureEnabled && $suma["name"]->__toString() === "overtureAds" )
							)
						)
					){

448
449
					# In eine if-Abfrage ???
					# Prüft ob die Suma ausgeschaltet ist ???
450
451
					if(!(isset($suma['disabled']) && $suma['disabled']->__toString() === "1"))
					{
452
						# Es ist Overture oder Overture Ads
453
454
455
456
						if($suma["name"]->__toString() === "overture" || $suma["name"]->__toString() === "overtureAds")
						{
							$overtureEnabled = TRUE;
						}
457
458

						# Es ist nicht Qualigo, Similar Product Ads oder Overture Ads
459
460
461
						if( $suma["name"]->__toString() !== "qualigo" && $suma["name"]->__toString() !== "similar_product_ads" && $suma["name"]->__toString() !== "overtureAds" )
							$countSumas += 1;
						$enabledSearchengines[] = $suma;
462
						# Soll das mit in das if ???
463
464
465
					}
				}
			}
466
467
		}else
		{
468
469
			foreach($sumas as $suma){
				$types = explode(",",$suma["type"]);
470
471
472
473
474
475
476
477
478
479
480
				/* Prüft ob die Suma zum eingeschalteten Fokus passt oder eine Werbe-Suma ist
				*  (Die Suma hat einen zum Fokus passenden Typ) oder 
				*  (	(Der Suchfokus ist nicht Bilder) und 
				* 		(	(Es ist Qualigo) oder 
				* 			(Es ist Similar Product Ads) oder 
				* 			(	(Overture ist nicht eingeschaltet) und 
				* 				(Es ist Overture Ads)
				* 			)
				* 		)
				* 	)
				*/
481
482
483
484
485
486
487
488
489
490
				if(in_array($this->fokus, $types) 
					|| ( $this->fokus !== "bilder" 
						&& ($suma["name"]->__toString() === "qualigo" 
							|| $suma["name"]->__toString() === "similar_product_ads" 
							|| ( !$overtureEnabled && $suma["name"]->__toString() === "overtureAds" )
							)
						)
					){
					if(!(isset($suma['disabled']) && $suma['disabled']->__toString() === "1"))
					{
491
						# Es ist Overture oder Overture Ads
492
493
494
495
						if($suma["name"]->__toString() === "overture" || $suma["name"]->__toString() === "overtureAds")
						{
							$overtureEnabled = TRUE;
						}
496
497

						# Es ist nicht Qualigo, Similar Product Ads oder Overture Ads
498
499
500
						if( $suma["name"]->__toString() !== "qualigo" && $suma["name"]->__toString() !== "similar_product_ads" && $suma["name"]->__toString() !== "overtureAds" )
							$countSumas += 1;
						$enabledSearchengines[] = $suma;
501
						# Soll das mit in das if ???
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
					}
				}
			}
		}

		# Sonderregelung für alle Suchmaschinen, die zu den Minisuchern gehören. Diese können alle gemeinsam über einen Link abgefragt werden
		$subcollections = [];
		$tmp = [];
		foreach($enabledSearchengines as $engine )
		{
			if( isset($engine['minismCollection']) )
				$subcollections[] = $engine['minismCollection']->__toString();
			else
				$tmp[] = $engine;
		}
		$enabledSearchengines = $tmp;
		if( sizeof($subcollections) > 0)
		{
			$count = sizeof($subcollections) * 10;
			$minisucherEngine = $xml->xpath('suma[@name="minism"]')[0];  
			$subcollections = urlencode("(" . implode(" OR ", $subcollections) . ")");
			$minisucherEngine["formData"] = str_replace("<<SUBCOLLECTIONS>>", $subcollections, $minisucherEngine["formData"]);
			$minisucherEngine["formData"] = str_replace("<<COUNT>>", $count, $minisucherEngine["formData"]);
			$enabledSearchengines[] = $minisucherEngine;
		}

528
		# Falls keine passenden Sumas gefunden wurden.
529
530
531
532
		if( $countSumas <= 0 )
		{
			$this->errors[] = "Achtung: Sie haben in ihren Einstellungen keine Suchmaschine ausgewählt.";
		}
533

534
		# Wenn eine Sitesearch durchgeführt werden soll, überprüfen wir ob eine der Suchmaschinen überhaupt eine Sitesearch unterstützt:
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
		$siteSearchFailed = false;
		if( strlen($this->site) > 0 )
		{
			$enginesWithSite = 0;
			foreach($enabledSearchengines as $engine)
			{
				if( isset($engine['hasSiteSearch']) && $engine['hasSiteSearch']->__toString() === "1" )
				{
					$enginesWithSite++;
				}
			}
			if( $enginesWithSite === 0 )
			{
				$this->errors[] = "Sie wollten eine Sitesearch auf " . $this->site . " durchführen. Leider unterstützen die eingestellten Suchmaschinen diese nicht. Sie können <a href=\"" . $this->generateSearchLink("web", false) . "\">hier</a> die Sitesearch im Web-Fokus durchführen. Es werden ihnen Ergebnisse ohne Sitesearch angezeigt.";
				$siteSearchFailed = true;
			}else
			{
				$this->warnings[] = "Sie führen eine Sitesearch durch. Es werden nur Ergebnisse von der Seite: <a href=\"http://" . $this->site . "\" target=\"_blank\">\"" . $this->site . "\"</a> angezeigt.";
			}

		}

		$typeslist = [];
		$counter = 0;
559

560
		# Erstellung der Suchengines
561
562
		
		$engines = [];
563
564
		foreach($enabledSearchengines as $engine){
			# Überspringt die Suchengine, falls eine Sitesearch aktiv ist, aber die Engine keine Sitesearch unterstützt.
565
566
567
568
569
570
			if( !$siteSearchFailed && strlen($this->site) > 0 && ( !isset($engine['hasSiteSearch']) || $engine['hasSiteSearch']->__toString() === "0")  )
			{
				
				continue;
			}

571
572
			# Überspringt die Suchengine, falls für sie kein Parserskript existiert.
			$path = "App\Models\parserSkripte\\" . ucfirst($engine["package"]->__toString());
573
574
575
576
577
578
			if( !file_exists(app_path() . "/Models/parserSkripte/" . ucfirst($engine["package"]->__toString()) . ".php"))
			{
				Log::error("Konnte " . $engine["name"] . " nicht abfragen, da kein Parser existiert");
				continue;
			}

579
			# Startet den Timer für die Erstellzeit ??? und versucht die Suchengine zu erstellen
580
581
582
583
584
585
586
587
588
589
590
			$time = microtime();

			try
			{
				$tmp = new $path($engine, $this);
			} catch( \ErrorException $e)
			{
				Log::error("Konnte " . $engine["name"] . " nicht abfragen." . var_dump($e));
				continue;
			}

591
			# isEnabled() ???
592
593
594
595
596
			if($tmp->enabled && isset($this->debug))
			{
				$this->warnings[] = $tmp->service . "   Connection_Time: " . $tmp->connection_time . "	Write_Time: " . $tmp->write_time . " Insgesamt:" . ((microtime()-$time)/1000);
			}

597
			# Trägt die Engine und den genutzten Socket in entsprechende Listen ein ???
598
599
600
601
602
603
604
605
			if($tmp->isEnabled())
			{
				$engines[] = $tmp;
				$this->sockets[$tmp->name] = $tmp->fp;
			}

		}

606
607
608
		# Automatische Einstellung des Tabs auf der Ergebnisseite

		# Jetzt werden noch alle Kategorien der Settings durchgegangen und die jeweils enthaltenen Namen der Suchmaschinen gespeichert.
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
		$foki = [];
		foreach($sumas as $suma)
		{
			if( (!isset($suma['disabled']) || $suma['disabled'] === "") && ( !isset($suma['userSelectable']) || $suma['userSelectable']->__toString() === "1") )
			{
				if( isset($suma['type']) )
				{
					$f = explode(",", $suma['type']->__toString());
					foreach($f as $tmp)
					{
						$name = $suma['name']->__toString();
						$foki[$tmp][$suma['name']->__toString()] = $name;
					}
				}else
				{
					$name = $suma['name']->__toString();
					$foki["andere"][$suma['name']->__toString()] = $name;
				}
			}
		}

		# Es werden auch die Namen der aktuell aktiven Suchmaschinen abgespeichert.
		$realEngNames = [];
		foreach($enabledSearchengines as $realEng) {
			$nam = $realEng["name"]->__toString();
			if($nam !== "qualigo" && $nam !== "overtureAds") {
				$realEngNames[] = $nam;
			}
		}
638

639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
		# Anschließend werden diese beiden Listen verglichen (jeweils eine der Fokuslisten für jeden Fokus), um herauszufinden ob sie vielleicht identisch sind. Ist dies der Fall, so hat der Nutzer anscheinend Suchmaschinen eines kompletten Fokus eingestellt. Der Fokus wird dementsprechend angepasst.
		foreach($foki as $fok => $engs) {
			$isFokus = true;
			$fokiEngNames = [];
			foreach($engs as $eng) {
				$fokiEngNames[] = $eng;
			}
			foreach($fokiEngNames as $fen) {
				if(!in_array($fen, $realEngNames)) {
					$isFokus = false;
				}
			}
			foreach($realEngNames as $ren) {
				if(!in_array($ren, $fokiEngNames)) {
					$isFokus = false;
				}
			}
			if($isFokus) {
				$this->fokus = $fok;
			}
		}
660

661
662
663
664
665
666
667
668
669
		# Suchvorgang

		/* Nun passiert ein elementarer Schritt.
		*  Wir warten auf die Antwort der Suchmaschinen, 
		*  da wir vorher nicht weiter machen können, 
		*  aber natürlich nicht ewig.
		*  Die Verbindung steht zu diesem Zeitpunkt und auch unsere Request wurde schon gesendet.
		*  Wir geben der Suchmaschine nun bis zu 500ms Zeit zu antworten.
		*/
670
671
672
673
674
675
676
677
678
679
680
681
682
		$enginesToLoad = count($engines);
		$loadedEngines = 0;
		$timeStart = microtime(true);

		while( true )
		{
			$time = (microtime(true) - $timeStart) * 1000;
			$loadedEngines = intval(Redis::hlen('search.' . $this->getHashCode()));
			$canBreak = true;
			if( $overtureEnabled && !Redis::hexists('search.' . $this->getHashCode(), 'overture') && !Redis::hexists('search.' . $this->getHashCode(), 'overtureAds'))
				$canBreak = false;


683
684
685
686
687
688
689
690
691
692
693
694
695
696
			/* Prüft abhängig von der bisher verstrichenen Zeit 
			*  ob schon genug Ergebnisse vorliegen, um mit Suchen aufzuhören:
			*  unter 0,5s 					: 
					(	(keine Suchmaschinen laden mehr) oder 
						(die Anzahl der zu ladenden Ergebnisse ist erreicht)
					) und (es darf abgebrochen werden)
			*  0,5s bis maximale Suchzeit 	: 
					(	(keine Suchmaschinen laden mehr) oder 
						(mindestens 80% der Suchmaschinen sind geladen)
					) und (es darf abgebrochen werden)
			*  über maximaler Suchzeit 		: 
					unbedingter Abbruch
			*/
			# canBreak bei enginesToLoad === 0 ???
697
698
			if($time < 500)
			{
699
				if( ($enginesToLoad === 0 || $loadedEngines >= $enginesToLoad) && $canBreak)
700
701
702
703
704
705
706
707
708
709
710
711
					break;
			}elseif( $time >= 500 && $time < $this->time)
			{
				if( ($enginesToLoad === 0 || ($loadedEngines / ($enginesToLoad * 1.0)) >= 0.8) && $canBreak )
					break;
			}else
			{
				break;
			}
			usleep(50000);
		}

712
		# Versucht alle Ergebnisse auszulesen
713
714
715
716
717
718
719
720
721
722
723
724
725
726
		foreach($engines as $engine)
		{
			if(!$engine->loaded)
			{
				try{
					$engine->retrieveResults();
				} catch(\ErrorException $e)
				{
					Log::error($e);
					
				}
			}
		}
		
727
		# und verwirft den Rest.
728
729
730
731
		foreach( $engines as $engine )
		{
			if( !$engine->loaded )
				$engine->shutdown();
732
		}
733

734
		$this->engines = $engines;
735
736
	}

737
738
739
740
741
	/** 
	*  Liest aus einer vom Nutzer abgesendete Anfrage die Suchparameter aus. Dazu gehören:
	*  
	*  url 				-	???
	*  fokus			-	Der gewählte Suchfokus
742
	*  sumaFile			-	Die Suma-Datei je nach Sprache
743
744
	*  eingabe			-	Die eingegebenen Suchbegriffe
	*  q				-	Erst einmal gleich wie eingabe
745
	*  ip				-	Die IP des Nutzers ??? anonymisiert ???
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
	*  language			-	???
	*  category			-	???
	*  time				-	Die maximale Suchzeit
	*  page				-	Die gewählte Ergebnisseite
	*  lang				-	Die gewählte Sprache der Suchergebnisse
	*  agent			-	Ein Agent - unter anderem zur Browser-, Sprach- und Mobilgeräteerkennung
	*  mobile			-	Nutzer auf Mobilgerät
	*  sprueche			-	Sprüche ein-/ausgeschaltet
	*  resultCount		-	Gewünschte Anzahl Ergebnisse pro Seite
	*  tab				-	gewählter Ergebnistab
	*  password			-	???
	*  quicktips		-	Quicktips ein-/ausgeschaltet
	*  out				-	???
	*  request			-	Sicherung der Anfrage
	*/

762
763
764
765
766
767
768
769
770
771
772
773
	public function parseFormData (Request $request)
	{
		if($request->input('encoding', '') !== "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);
		}
774

775
		$this->url = $request->url();
776

777
		# Zunächst überprüfen wir die eingegebenen Einstellungen:
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
		# FOKUS
		$this->fokus = trans('fokiNames.'
			. $request->input('focus', 'web'));
		if(strpos($this->fokus,"."))
		{
			$this->fokus = trans('fokiNames.web');
		}

		# SUMA-FILE
		if(App::isLocale("en")){
			$this->sumaFile = config_path() . "/sumas.xml";
		}else{
			$this->sumaFile = config_path() . "/sumas.xml";
		}
		if(!file_exists($this->sumaFile))
		{
			die("Suma-File konnte nicht gefunden werden");
		}

		# Sucheingabe:
		$this->eingabe = trim($request->input('eingabe', ''));
		if(strlen($this->eingabe) === 0)
		{
			$this->warnings[] = 'Achtung: Sie haben keinen Suchbegriff eingegeben. Sie können ihre Suchbegriffe oben eingeben und es erneut versuchen.';
		}
		$this->q = $this->eingabe;

		# IP:
		$this->ip = $request->ip();

		# Language:
		if( isset($_SERVER['HTTP_LANGUAGE']) )
		{
			$this->language = $_SERVER['HTTP_LANGUAGE'];
		}else
		{
			$this->language = "";
		}
816

817
818
		# Category
		$this->category = $request->input('category', '');
819

820
821
822
823
824
		# Request Times:
		$this->time = $request->input('time', 1000);
	   
		# Page
		$this->page = $request->input('page', 1);
825

826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
		# Lang
		$this->lang = $request->input('lang', 'all');
		if ( $this->lang !== "de" && $this->lang !== "en" && $this->lang !== "all" )
		{
			$this->lang = "all";
		}
		$this->agent = new Agent();
		$this->mobile = $this->agent->isMobile();

		#Sprüche
		$this->sprueche = $request->input('sprueche', 'off');
		if($this->sprueche === "off" )
			$this->sprueche = true;
		else
			$this->sprueche = false;
		# Ergebnisse pro Seite:
		$this->resultCount = $request->input('resultCount', '20');

		# Manchmal müssen wir Parameter anpassen um den Sucheinstellungen gerecht zu werden:
845
		# Dart-Europe - mehr Suchzeit
846
847
848
849
850
		if( $request->has('dart') )
		{
			$this->time = 10000;
			$this->warnings[] = "Hinweis: Sie haben Dart-Europe aktiviert. Die Suche kann deshalb länger dauern und die maximale Suchzeit wurde auf 10 Sekunden hochgesetzt.";
		}
851
852

		# Falscher Zeitrahmen - Auf Standardwert setzen
853
854
855
856
		if( $this->time <= 500 || $this->time > 20000 )
		{
			$this->time = 1000;
		}
857
858

		# Minism - ???
859
860
861
862
863
864
865
866
867
868
869
870
871
		if( $request->has('minism') && ( $request->has('fportal') || $request->has('harvest') ) )
		{
			$input = $request->all();
			$newInput = [];
			foreach($input as $key => $value)
			{
				if( $key !== "fportal" && $key !== "harvest" )
				{
					$newInput[$key] = $value;
				}
			}
			$request->replace($newInput);
		}
872
873

		# Ebay - extra Suchzeit
874
875
876
877
878
		if( $request->has('ebay') )
		{
			$this->time = 2000;
			$this->warnings[] = "Hinweis: Sie haben Ebay aktiviert. Die Suche kann deshalb länger dauern und die maximale Suchzeit wurde auf 2 Sekunden hochgesetzt.";
		}
879
880

		# Englisch - keine Sprüche
881
882
883
884
		if( App::isLocale("en") )
		{
			$this->sprueche = "off";
		}
885

886
		# Falsche Anzahl maximale Ergebnisse - Standartwert 1000
887
888
889
890
		if($this->resultCount <= 0 || $this->resultCount > 200 )
		{
			$this->resultCount = 1000;
		}
891
892

		# Onenewspage - Mehr Zeit und Cache
893
894
895
896
897
		if( $request->has('onenewspageAll') || $request->has('onenewspageGermanyAll') )
		{
			$this->time = 5000;
			$this->cache = "cache";
		}
898

899
		# Den richtigen Tab einstellen
900
901
902
903
904
905
906
907
908
909
910
911
912
		if( $request->has('tab'))
		{
			if($request->input('tab') === "off")
			{
				$this->tab = "_blank";
			}else
			{
				$this->tab = "_self";
			}
		}else
		{
			$this->tab = "_blank";
		}
913
914

		# Password setzen
915
916
		if( $request->has('password') )
			$this->password = $request->input('password');
917
918

		# Quicktips an-/ausschalten
919
920
921
922
923
		if( $request->has('quicktips') )
			$this->quicktips = false;
		else
			$this->quicktips = true;

924
		# Output-Format festlegen
925
926
927
		$this->out = $request->input('out', "html");
		if($this->out !== "html" && $this->out !== "json" && $this->out !== "results" && $this->out !== "results-with-style")
			$this->out = "html";
928
929

		# Request abspeichern
930
		$this->request = $request;
931
932
	}

933
934
	# Liest aus der Sucheingabe bestimmte Spezialsuchen aus
	# Arbeitet auf der Variable q
935
936
937
	public function checkSpecialSearches (Request $request)
	{
		# Site Search:
938
		# Wenn die Suchanfrage um das Schlüsselwort "site:*" ergänzt ist, sollen Ergebnisse nur von einer bestimmten Seite stammen.
939
940
941
942
943
		if(preg_match("/(.*)\bsite:(\S+)(.*)/si", $this->q, $match))
		{
			$this->site = $match[2];
			$this->q = $match[1] . $match[3];
		}
944
945
946
947
		if( $request->has('site') )
		{
			$this->site = $request->input('site');
		}
948
949
950

		# Host-Blacklisting:
		# Wenn die Suchanfrage um das Schlüsselwort "-host:*" ergänzt ist, sollen bestimmte Hosts nicht eingeblendet werden.
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
		while(preg_match("/(.*)(^|\s)-host:(\S+)(.*)/si", $this->q, $match))
		{
			$this->hostBlacklist[] = $match[3];
			$this->q = $match[1] . $match[4];
		}
		if( sizeof($this->hostBlacklist) > 0 )
		{
			$hostString = "";
			foreach($this->hostBlacklist as $host)
			{
				$hostString .= $host . ", ";
			}
			$hostString = rtrim($hostString, ", ");
			$this->warnings[] = "Ergebnisse von folgenden Hosts werden nicht angezeigt: \"" . $hostString . "\"";
		}
966
967
968

		# Domain-Blacklisting:
		# Wenn die Suchanfrage um das Schlüsselwort "-domain:*" ergänzt ist, sollen bestimmte Domains nicht eingeblendet werden.
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
		while(preg_match("/(.*)(^|\s)-domain:(\S+)(.*)/si", $this->q, $match))
		{
			$this->domainBlacklist[] = $match[3];
			$this->q = $match[1] . $match[4];
		}
		if( sizeof($this->domainBlacklist) > 0 )
		{
			$domainString = "";
			foreach($this->domainBlacklist as $domain)
			{
				$domainString .= $domain . ", ";
			}
			$domainString = rtrim($domainString, ", ");
			$this->warnings[] = "Ergebnisse von folgenden Domains werden nicht angezeigt: \"" . $domainString . "\"";
		}
		
985
		# Stopwords:
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
		# Alle mit "-" gepräfixten Worte sollen aus der Suche ausgeschlossen werden.
		while(preg_match("/(.*)(^|\s)-(\S+)(.*)/si", $this->q, $match))
		{
			$this->stopWords[] = $match[3];
			$this->q = $match[1] . $match[4];
		}
		if( sizeof($this->stopWords) > 0 )
		{
			$stopwordsString = "";
			foreach($this->stopWords as $stopword)
			{
				$stopwordsString .= $stopword . ", ";
			}
			$stopwordsString = rtrim($stopwordsString, ", ");
			$this->warnings[] = "Sie machen eine Ausschlusssuche. Ergebnisse mit folgenden Wörtern werden nicht angezeigt: \"" . $stopwordsString . "\"";
		}

1003
1004
		# Phrasensuche:
		# Alle mit " umschlossenen Worte gelten als Phrasensuche und sollen in genau dieser Reihenfolge im Suchergebnis vorkommen.
1005
1006
		$p = "";
		$tmp = $this->q;
1007
		while(preg_match("/(.*)\"(.+)\"(.*)/si", $tmp, $match)){
1008
1009
1010
1011
1012
1013
			$tmp = $match[1] . $match[3];
			$this->phrases[] = strtolower($match[2]);
		}
		foreach($this->phrases as $phrase)
		{
			$p .= "\"$phrase\", ";
1014
		}
1015
1016
1017
1018
1019
		$p = rtrim($p, ", ");
		if(sizeof($this->phrases) > 0)
			$this->warnings[] = "Sie führen eine Phrasensuche durch: $p";
	}

1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
	# Hilfsmethoden

	# Adder

	public function addHostCount($host)
	{
		$hash = md5($host);
		if(isset($this->addedHosts[$hash]))
		{
			$this->addedHosts[$hash] += 1;
		}else
		{
			$this->addedHosts[$hash] = 1;
		}
	}

	public function addLink($link)
	{
		if(strpos($link, "http://") === 0)
			$link = substr($link, 7);
		if(strpos($link, "https://") === 0)
			$link = substr($link, 8);
		if(strpos($link, "www.") === 0)
			$link = substr($link, 4);
		$link = trim($link, "/");
		$hash = md5($link);
		if(isset($this->addedLinks[$hash]))
		{
			return false;
		}else
		{
			$this->addedLinks[$hash] = 1;

			return true;
		}
	}

	# Generators

	public function generateSearchLink($fokus, $results = true)
	{
		$requestData = $this->request->except('page');
		$requestData['focus'] = $fokus;
		if($results)
			$requestData['out'] = "results";
		else
			$requestData['out'] = "";
		$link = action('MetaGerSearch@search', $requestData);
		return $link;
	}

	public function generateQuicktipLink()
	{
		$link = action('MetaGerSearch@quicktips');

		return $link;
	}

	public function generateSiteSearchLink($host)
	{
		$host = urlencode($host);
		$requestData = $this->request->except(['page','out']);
		$requestData['eingabe'] .= " site:$host";
		$requestData['focus'] = "web";
		$link = action('MetaGerSearch@search', $requestData);
		return $link;
	}

	public function generateRemovedHostLink ($host)
	{
		$host = urlencode($host);
		$requestData = $this->request->except(['page','out']);
		$requestData['eingabe'] .= " -host:$host";
		$link = action('MetaGerSearch@search', $requestData);
		return $link;
	}

	public function generateRemovedDomainLink ($domain)
	{
		$domain = urlencode($domain);
		$requestData = $this->request->except(['page','out']);
		$requestData['eingabe'] .= " -domain:$domain";
		$link = action('MetaGerSearch@search', $requestData);
		return $link;
	}

	# Popper

	public function popAd()
	{
		if(count($this->ads) > 0)
			return get_object_vars(array_shift($this->ads));
		else
			return null;
	}

	# Getter

1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
	public function getFokus ()
	{
		return $this->fokus;
	}

	public function getIp ()
	{
		return $this->ip;
	}

	public function getEingabe ()
	{
		return $this->eingabe;
	}

	public function getQ ()
	{
			return $this->q;
	}

	public function getUrl ()
	{
		return $this->url;
	}
	public function getTime ()
	{
		return $this->time;
	}

	public function getLanguage ()
	{
		return $this->language;
	}

	public function getLang ()
	{
		return $this->lang;
	}

	public function getSprueche ()
	{
		return $this->sprueche;
1160
	}
1161

1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
	public function getCategory ()
	{
		return $this->category;
	}

	public function getPhrases ()
	{
		return $this->phrases;
	}

	public function getSumaFile ()
	{
		return $this->sumaFile;
	}

	public function getUserHostBlacklist ()
	{
		return $this->hostBlacklist;
	}

	public function getUserDomainBlacklist ()
	{
		return $this->domainBlacklist;
	}

	public function getDomainBlacklist ()
	{
		return $this->domainsBlacklisted;
	}

	public function getUrlBlacklist ()
	{
		return $this->urlsBlacklisted;
	}
	public function getLanguageDetect ()
	{
		return $this->languageDetect;
	}
	public function getStopWords ()
	{
		return $this->stopWords;
	}
	public function getHostCount($host)
	{
		if(isset($this->addedHosts[$host]))
		{
			return $this->addedHosts[$host];
		}else
		{
			return 0;
		}
	}

1215
	public function getTab ()
1216
	{
1217
		return $this->tab;
1218
1219
	}

1220
	public function getResults ()
1221
	{
1222
		return $this->results;
1223
1224
	}

1225
	public function getImageProxyLink($link)
1226
	{
1227
1228
1229
		$requestData = [];
		$requestData["url"] = $link;
		$link = action('Pictureproxy@get', $requestData);
1230
1231
1232
		return $link;
	}

1233
	public function getSite()
1234
	{
1235
		return $this->site;
1236
1237
	}

1238
	public function getHashCode ()
1239
	{
1240
1241
		$string = url()->full();
		return md5($string);
1242
1243
	}

1244
1245
	# Shower

1246
1247
1248
1249
	public function showQuicktips ()
	{
		return $this->quicktips;
	}
Phil Höfer's avatar
Phil Höfer committed
1250
}