-
Dominik Hebeler authoredDominik Hebeler authored
Result.php 17.33 KiB
<?php
namespace App\Models;
/* Die Klasse Result sammelt alle Informationen über ein einzelnes Suchergebnis.
* Die Results werden von den Suchmaschinenspezifischen Parser-Skripten erstellt.
*/
class Result
{
public $provider; # Die Engine von der das Suchergebnis kommt
public $titel; # Der Groß Angezeigte Name für das Suchergebnis
public $link; # Der Link auf die Ergebnisseite
public $anzeigeLink; # Der tatsächlich angezeigte Link (rein optisch)
public $descr; # Die eventuell gekürzte Beschreibung des Suchergebnisses
public $longDescr; # Die ungekürzte Beschreibung des Suchergebnisses
public $gefVon = []; # Die Suchmaschine von der dieses Ergebnis stammt
public $gefVonLink = [];
public $sourceRank; # Das Ranking für dieses Suchergebnis von der Seite, die es geliefert hat (implizit durch Ergebnisreihenfolge: 20 - Position in Ergebnisliste)
public $partnershop; # Ist das Ergebnis von einem Partnershop? (bool)
public $image; # Ein Vorschaubild für das Suchergebnis (als URL)
public $proxyLink; # Der Link für die Seite über unseren Proxy-Service
public $engineBoost = 1; # Der Boost für den Provider des Suchergebnisses
public $valid = true; # Ob das Ergebnis noch gültig ist (bool)
public $host; # Der aus dem Link gelesene Host des Suchergebnisses
public $strippedHost; # Der Host in Form "foo.bar.de"
public $strippedDomain; # Die Domain in Form "bar.de"
public $strippedLink; # Der Link in Form "foo.bar.de/test"
public $strippedHostAnzeige; # Der Host in Form "foo.bar.de"
public $strippedDomainAnzeige; # Die Domain in Form "bar.de"
public $strippedLinkAnzeige; # Der Link in Form "foo.bar.de/test"
public $rank; # Das Ranking für das Ergebnis
public $new = true;
public $changed = false;
const DESCRIPTION_LENGTH = 150;
# Erstellt ein neues Ergebnis
public function __construct($provider, $titel, $link, $anzeigeLink, $descr, $gefVon, $gefVonLink, $sourceRank, $additionalInformation = [])
{
$this->provider = $provider;
$this->titel = strip_tags(trim($titel));
$this->link = trim($link);
$this->anzeigeLink = trim($anzeigeLink);
$this->anzeigeLink = preg_replace("/(http[s]{0,1}:\/\/){0,1}(www\.){0,1}/si", "", $this->anzeigeLink);
$this->descr = strip_tags(trim($descr), '<p>');
$this->descr = preg_replace("/\n+/si", " ", $this->descr);
$this->longDescr = $this->descr;
if (strlen($this->descr) > self::DESCRIPTION_LENGTH) {
$this->descr = wordwrap($this->descr, self::DESCRIPTION_LENGTH);
$this->descr = substr($this->descr, 0, strpos($this->descr, "\n"));
$this->descr .= "…"; // Ellipsis character
}
$this->gefVon[] = trim($gefVon);
$this->gefVonLink[] = trim($gefVonLink);
$this->proxyLink = $this->generateProxyLink($this->link);
$this->sourceRank = $sourceRank;
if ($this->sourceRank <= 0 || $this->sourceRank > 20) {
$this->sourceRank = 20;
}
$this->sourceRank = 20 - $this->sourceRank;
if (isset($provider->{"engine-boost"})) {
$this->engineBoost = floatval($provider->{"engine-boost"});
} else {
$this->engineBoost = 1;
}
$this->valid = true;
$this->host = @parse_url($link, PHP_URL_HOST);
$this->strippedHost = $this->getStrippedHost($this->link);
$this->strippedDomain = $this->getStrippedDomain($this->link);
$this->strippedLink = $this->getStrippedLink($this->link);
$this->strippedHostAnzeige = $this->getStrippedHost($this->anzeigeLink);
$this->strippedDomainAnzeige = $this->getStrippedDomain($this->anzeigeLink);
$this->strippedLinkAnzeige = $this->getStrippedLink($this->anzeigeLink);
$this->rank = 0;
$this->partnershop = isset($additionalInformation["partnershop"]) ? $additionalInformation["partnershop"] : false;
$this->image = isset($additionalInformation["image"]) ? $additionalInformation["image"] : "";
$this->price = isset($additionalInformation["price"]) ? $additionalInformation["price"] : 0;
$this->price_text = $this->price_to_text($this->price);
$this->additionalInformation = $additionalInformation;
$this->hash = spl_object_hash($this);
}
private function price_to_text($price)
{
$euros = floor($price / 100);
$cents = $price % 100;
$price_text = $euros . ',';
if ($cents < 10) {
$price_text .= '0';
}
$price_text .= $cents . ' €';
return $price_text;
}
/* Ranked das Ergebnis nach folgenden Aspekten:
* Startwert 0
* + 0.02 * Sourcerank (20 - Position in Ergebnisliste des Suchanbieters)
* * Engine-Boost
*/
public function rank($eingabe)
{
$rank = 0;
# Boost für Source Ranking
$rank += ($this->sourceRank * 0.02);
# Boost für passende ??? URL
$rank += $this->calcURLBoost($eingabe);
# Boost für Vorkommen der Suchwörter:
$rank += $this->calcSuchwortBoost($eingabe);
# Boost für Suchmaschine
if ($this->engineBoost > 0) {
$rank *= floatval($this->engineBoost);
}
# Runter Ranken von Yandex Ergebnissen mit zu viel kyrillischen Texten
if (stripos($this->gefVon[0], "yandex") !== false) {
$rank -= $this->calcYandexBoost($eingabe);
}
$this->rank = $rank;
}
# Berechnet, ob dieses Suchergebnis einen Malus erhalten soll, oder nicht
# Übergeben werden alle Yandex Ergebnisse
# Wenn die Suchworte kein kyrillisches Zeichen enthalten, wird das Ergebnis schlechter bewertet,
# falls es selbst zu viele kyrillische Zeichen enthält
private function calcYandexBoost($tmpEingabe)
{
$maxRatio = 0.1; # Gibt den Prozentsatz von Kyrillischen Zeichen in Titel und Beschreibung an, ab dem das Ergebnis runter gerankt werden soll
if (preg_match('/[А-Яа-яЁё]/u', $tmpEingabe) === 1) {
# Das Suchwort enthält kyrillische Zeichen, also dürfen es auch die Ergebnisse
return 0;
} else {
# Wir überprüfen das Verhältnis von Kyrillischen Zeichen im Titel
if (preg_match_all('/[А-Яа-яЁё]/u', $this->titel, $matches)) {
$count = sizeof($matches[0]);
$titleSize = strlen($this->titel);
$percKyr = $count / $titleSize;
if ($percKyr > $maxRatio) {
return 5;
}
}
# Wir überprüfen das Verhältnis von Kyrillischen Zeichen in der Beschreibung
if (preg_match_all('/[А-Яа-яЁё]/u', $this->descr, $matches)) {
$count = sizeof($matches[0]);
$descrSize = strlen($this->descr);
$percKyr = $count / $descrSize;
if ($percKyr > $maxRatio) {
return 5;
}
}
}
return 0;
}
# Berechnet den Ranking-Boost durch ??? URL
public function calcURLBoost($tmpEingabe)
{
$link = $this->anzeigeLink;
if (strpos($link, "http") !== 0) {
$link = "http://" . $link;
}
$link = @parse_url($link, PHP_URL_HOST) . @parse_url($link, PHP_URL_PATH);
$tmpLi = $link;
$count = 0;
$tmpLink = "";
# Löscht verschiedene unerwünschte Teile aus $link und $tmpEingabe
$regex = [
"/\s+/si", # Leerzeichen
"/http:/si", # "http:"
"/https:/si", # "https:"
"/www\./si", # "www."
"/\//si", # "/"
"/\./si", # "."
"/-/si", # "-"
];
foreach ($regex as $reg) {
$link = preg_replace($regex, "", $link);
$tmpEingabe = preg_replace($regex, "", $tmpEingabe);
}
foreach (str_split($tmpEingabe) as $char) {
if (!$char
|| !$tmpEingabe
|| strlen($tmpEingabe) === 0
|| strlen($char) === 0
) {
continue;
}
if (strpos(strtolower($tmpLink), strtolower($char)) >= 0) {
$count++;
$tmpLink = str_replace(urlencode($char), "", $tmpLink);
}
}
if (strlen($this->descr) > 40 && strlen($link) > 0) {
return $count / ((strlen($link)) * 60); # ???
} else {
return 0;
}
}
# Berechnet den Ranking-Boost durch das Vorkommen von Suchwörtern
private function calcSuchwortBoost($tmpEingabe)
{
$maxRank = 0.1;
$tmpTitle = $this->titel;
$tmpDescription = $this->descr;
$isWithin = false;
$tmpRank = 0;
$tmpEingabe = preg_replace("/\b\w{1,3}\b/si", "", $tmpEingabe);
$tmpEingabe = preg_replace("/\s+/si", " ", $tmpEingabe);
foreach (explode(" ", trim($tmpEingabe)) as $el) {
if (strlen($tmpTitle) === 0 || strlen($el) === 0 || strlen($tmpDescription) === 0) {
continue;
}
$el = preg_quote($el, "/");
if (strlen($tmpTitle) > 0) {
if (preg_match("/\b$el\b/si", $tmpTitle)) {
$tmpRank += .7 * .6 * $maxRank;
} elseif (strpos($tmpTitle, $el) !== false) {
$tmpRank += .3 * .6 * $maxRank;
}
}
if (strlen($tmpDescription) > 0) {
if (preg_match("/\b$el\b/si", $tmpDescription)) {
$tmpRank += .7 * .4 * $maxRank;
} elseif (strpos($tmpDescription, $el) !== false) {
$tmpRank += .3 * .4 * $maxRank;
}
}
}
$tmpRank /= sizeof(explode(" ", trim($tmpEingabe))) * 10;
return $tmpRank;
}
# Überprüft ob das Ergebnis aus irgendwelchen Gründen unerwünscht ist.
public function isValid(\App\MetaGer $metager)
{
# Perönliche Host und Domain Blacklist
if (in_array(strtolower($this->strippedHost), $metager->getUserHostBlacklist())
|| in_array(strtolower($this->strippedDomain), $metager->getUserDomainBlacklist())) {
return false;
}
# Persönliche URL Blacklist
foreach ($metager->getUserUrlBlacklist() as $word) {
if (strpos(strtolower($this->link), $word)) {
return false;
}
}
# Allgemeine URL und Domain Blacklist
if ($this->isBlackListed($metager)) {
return false;
}
# Stopworte
foreach ($metager->getStopWords() as $stopWord) {
$text = $this->titel . " " . $this->descr;
if (stripos($text, $stopWord) !== false) {
return false;
}
}
/*
# Phrasensuche:
$text = strtolower($this->titel) . " " . strtolower($this->descr);
foreach ($metager->getPhrases() as $phrase) {
if (strpos($text, $phrase) === false) {
return false;
}
}
*/
/* Der Dublettenfilter, der sicher stellt,
* dass wir nach Möglichkeit keinen Link doppelt in der Ergebnisliste haben.
$dublettenLink = $this->strippedLink;
if (!empty($this->provider->{"dubletten-include-parameter"}) && sizeof($this->provider->{"dubletten-include-parameter"}) > 0) {
$dublettenLink .= "?";
$query = parse_url($this->link);
if (!empty($query["query"])) {
$queryTmp = explode("&", $query["query"]);
$query = [];
foreach ($queryTmp as $getParameter) {
$keyVal = explode("=", $getParameter);
$query[$keyVal[0]] = $keyVal[1];
}
foreach ($this->provider->{"dubletten-include-parameter"} as $param) {
if (!empty($query[$param])) {
$dublettenLink .= $param . "=" . $query[$param] . "&";
}
}
$dublettenLink = rtrim($dublettenLink, "&");
}
}
if ($metager->addLink($this)) {
$metager->addHostCount($this->strippedHost);
return true;
} else {
return false;
}*/
return true;
}
public function isBlackListed(\App\MetaGer $metager)
{
if (($this->strippedHost !== "" && (in_array($this->strippedHost, $metager->getDomainBlacklist()) ||
in_array($this->strippedLink, $metager->getUrlBlacklist()))) ||
($this->strippedHostAnzeige !== "" && (in_array($this->strippedHostAnzeige, $metager->getDomainBlacklist()) ||
in_array($this->strippedLinkAnzeige, $metager->getUrlBlacklist())))) {
return true;
} else {
return false;
}
}
/* Liest aus einem Link den Host.
* Dieser wird dabei in die Form:
* "http://www.foo.bar.de/test?ja=1" -> "foo.bar.de"
* gebracht.
*/
public function getStrippedHost($link)
{
$match = $this->getUrlElements($link);
return $match['host'];
}
/* Entfernt "http://", "www" und Parameter von einem Link
* Dieser wird dabei in die Form:
* "http://www.foo.bar.de/test?ja=1" -> "foo.bar.de/test"
* gebracht.
*/
public function getStrippedLink($link)
{
$match = $this->getUrlElements($link);
return $match['host'] . $match['path'];
}
/* Liest aus einem Link die Domain.
* Dieser wird dabei in die Form:
* "http://www.foo.bar.de/test?ja=1" -> "bar.de"
* gebracht.
*/
public function getStrippedDomain($link)
{
$match = $this->getUrlElements($link);
return $match['domain'];
}
# Erstellt aus einem Link einen Proxy-Link für unseren Proxy-Service
public function generateProxyLink($link)
{
if (!$link || empty($link)) {
return "";
}
$parts = parse_url($link);
$proxyUrl = "https://proxy.metager.de/";
if(!empty($parts["host"])){
$proxyUrl .= $parts["host"];
if(!empty($parts["path"])){
$proxyUrl .= "/" . trim($parts["path"], "/");
}
}
// We need to generate the correct password for the Proxy URLs
// It's an hmac sha256 hash of the url having the proxy password as secret
$password = hash_hmac("sha256", $link, env("PROXY_PASSWORD", "unsecure_password"));
$urlParameters = [
"url" => $link,
"password" => $password,
];
$params = http_build_query($urlParameters, "", "&", PHP_QUERY_RFC3986);
$proxyUrl .= "?" . $params;
return $proxyUrl;
}
/* Liest aus einer URL alle Informationen aus
* https://max:muster@www.example.site.page.com:8080/index/indexer/list.html?p1=A&p2=B#ressource
* (?:((?:http)|(?:https))(?::\/\/))?
* https:// => [1] = http / https
* (?:([a-z0-9.\-_~]+):([a-z0-9.\-_~]+)@)?
* username:password@ => [2] = username, [3] = password
* (?:(www)(?:\.))?
* www. => [4] = www
* ((?:(?:[a-z0-9.\-_~]+\.)+)?([a-z0-9.\-_~]+\.[a-z0-9.\-_~]+))
* example.site.page.com => [5] = example.site.page.com, [6] = page.com
* (?:(?::)(\d+))?
* :8080 => [7] = 8080
* ((?:(?:\/[a-z0-9.\-_~]+)+)(?:\.[a-z0-9.\-_~]+)?)?
* /index/indexer/list.html => [8] = /index/indexer/list.html
* (\?[a-z0-9.\-_~]+=[a-z0-9.\-_~]+(?:&[a-z0-9.\-_~]+=[a-z0-9.\-_~]+)*)?
* ?p1=A&p2=B => [9] = ?p1=A&p2=B
* (?:(?:#)([a-z0-9.\-_~]+))?
* #ressource => [10] = ressource
*/
public function getUrlElements($url)
{
if (!starts_with($url, "http")) {
$url = "http://" . $url;
}
$parts = parse_url($url);
$re = [];
$re["schema"] = empty($parts["scheme"]) ? "" : $parts["scheme"];
$re["username"] = empty($parts["user"]) ? "" : $parts["user"];
$re["password"] = empty($parts["pass"]) ? "" : $parts["pass"];
$re["web"] = "";
$re["host"] = $parts["host"];
if (stripos($re["host"], "www.") === 0) {
$re["web"] = "www.";
$re["host"] = substr($re["host"], strpos($re["host"], ".") + 1);
}
$hostParts = explode(".", $re["host"]);
if (sizeof($hostParts) >= 3) {
$re["domain"] = $hostParts[sizeof($hostParts) - 2] . "." . $hostParts[sizeof($hostParts) - 1];
} else {
$re["domain"] = $re["host"];
}
$re["port"] = empty($parts["port"]) ? ($re["schema"] === "http" ? 80 : ($re["schema"] === "https" ? 443 : 80)) : $parts["port"];
$re["path"] = empty($parts["path"]) ? "" : $parts["path"];
$re["query"] = empty($parts["query"]) ? "" : $parts["query"];
$re["fragment"] = empty($parts["fragment"]) ? "" : $parts["fragment"];
return $re;
}
# Getter
public function getRank()
{
return $this->rank;
}
public function getDate()
{
if (isset($this->additionalInformation["date"])) {
return $this->additionalInformation["date"];
} else {
return null;
}
}
public function getLangString()
{
$string = "";
$string .= $this->titel;
$string .= $this->descr;
return $string;
}
}