mirror of
https://github.com/shlinkio/shlink.git
synced 2026-03-10 17:23:12 +08:00
Added detection of visits from potential bots
This commit is contained in:
@@ -13,6 +13,8 @@ use Shlinkio\Shlink\Core\Model\Visitor;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitLocationInterface;
|
||||
use Shlinkio\Shlink\Importer\Model\ImportedShlinkVisit;
|
||||
|
||||
use function Shlinkio\Shlink\Core\isCrawler;
|
||||
|
||||
class Visit extends AbstractEntity implements JsonSerializable
|
||||
{
|
||||
public const TYPE_VALID_SHORT_URL = 'valid_short_url';
|
||||
@@ -29,6 +31,7 @@ class Visit extends AbstractEntity implements JsonSerializable
|
||||
private string $type;
|
||||
private ?ShortUrl $shortUrl;
|
||||
private ?VisitLocation $visitLocation = null;
|
||||
private bool $potentialBot;
|
||||
|
||||
private function __construct(?ShortUrl $shortUrl, string $type)
|
||||
{
|
||||
@@ -49,6 +52,7 @@ class Visit extends AbstractEntity implements JsonSerializable
|
||||
{
|
||||
$instance = new self($shortUrl, self::TYPE_IMPORTED);
|
||||
$instance->userAgent = $importedVisit->userAgent();
|
||||
$instance->potentialBot = isCrawler($instance->userAgent);
|
||||
$instance->referer = $importedVisit->referer();
|
||||
$instance->date = Chronos::instance($importedVisit->date());
|
||||
|
||||
@@ -88,6 +92,7 @@ class Visit extends AbstractEntity implements JsonSerializable
|
||||
$this->referer = $visitor->getReferer();
|
||||
$this->remoteAddr = $this->processAddress($anonymize, $visitor->getRemoteAddress());
|
||||
$this->visitedUrl = $visitor->getVisitedUrl();
|
||||
$this->potentialBot = $visitor->isPotentialBot();
|
||||
}
|
||||
|
||||
private function processAddress(bool $anonymize, ?string $address): ?string
|
||||
@@ -166,6 +171,7 @@ class Visit extends AbstractEntity implements JsonSerializable
|
||||
'date' => $this->date->toAtomString(),
|
||||
'userAgent' => $this->userAgent,
|
||||
'visitLocation' => $this->visitLocation,
|
||||
'potentialBot' => $this->potentialBot,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Psr\Http\Message\ServerRequestInterface;
|
||||
use Shlinkio\Shlink\Common\Middleware\IpAddressMiddlewareFactory;
|
||||
use Shlinkio\Shlink\Core\Options\TrackingOptions;
|
||||
|
||||
use function Shlinkio\Shlink\Core\isCrawler;
|
||||
use function substr;
|
||||
|
||||
final class Visitor
|
||||
@@ -21,6 +22,7 @@ final class Visitor
|
||||
private string $referer;
|
||||
private string $visitedUrl;
|
||||
private ?string $remoteAddress;
|
||||
private bool $potentialBot;
|
||||
|
||||
public function __construct(string $userAgent, string $referer, ?string $remoteAddress, string $visitedUrl)
|
||||
{
|
||||
@@ -28,6 +30,7 @@ final class Visitor
|
||||
$this->referer = $this->cropToLength($referer, self::REFERER_MAX_LENGTH);
|
||||
$this->visitedUrl = $this->cropToLength($visitedUrl, self::VISITED_URL_MAX_LENGTH);
|
||||
$this->remoteAddress = $this->cropToLength($remoteAddress, self::REMOTE_ADDRESS_MAX_LENGTH);
|
||||
$this->potentialBot = isCrawler($userAgent);
|
||||
}
|
||||
|
||||
private function cropToLength(?string $value, int $length): ?string
|
||||
@@ -70,14 +73,22 @@ final class Visitor
|
||||
return $this->visitedUrl;
|
||||
}
|
||||
|
||||
public function isPotentialBot(): bool
|
||||
{
|
||||
return $this->potentialBot;
|
||||
}
|
||||
|
||||
public function normalizeForTrackingOptions(TrackingOptions $options): self
|
||||
{
|
||||
$instance = self::emptyInstance();
|
||||
$instance = new self(
|
||||
$options->disableUaTracking() ? '' : $this->userAgent,
|
||||
$options->disableReferrerTracking() ? '' : $this->referer,
|
||||
$options->disableIpTracking() ? null : $this->remoteAddress,
|
||||
$this->visitedUrl,
|
||||
);
|
||||
|
||||
$instance->userAgent = $options->disableUaTracking() ? '' : $this->userAgent;
|
||||
$instance->referer = $options->disableReferrerTracking() ? '' : $this->referer;
|
||||
$instance->remoteAddress = $options->disableIpTracking() ? null : $this->remoteAddress;
|
||||
$instance->visitedUrl = $this->visitedUrl;
|
||||
// Keep the fact that the visit was a potential bot, even if we no longer save the user agent
|
||||
$instance->potentialBot = $this->potentialBot;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user