src/Entity/System/IpAddress.php line 16

Open in your IDE?
  1. <?php
  2. namespace App\Entity\System;
  3. use App\Entity\Profile\Comment\CommentByCustomer;
  4. use App\Repository\IpAddressRepository;
  5. use Carbon\CarbonImmutable;
  6. use Doctrine\Common\Collections\ArrayCollection;
  7. use Doctrine\Common\Collections\Collection;
  8. use Doctrine\Common\Collections\Criteria;
  9. use Doctrine\ORM\Mapping as ORM;
  10. use IPTools\Network;
  11. #[ORM\Table(name'ip_addresses')]
  12. #[ORM\Entity(repositoryClassIpAddressRepository::class)]
  13. class IpAddress
  14. {
  15.     #[ORM\Id]
  16.     #[ORM\Column(name'id'type'integer')]
  17.     #[ORM\GeneratedValue(strategy'AUTO')]
  18.     protected int $id;
  19.     /**
  20.      * Human-readable representation of the ip address or range
  21.      *
  22.      * Use binary range representation for ip lookup.
  23.      */
  24.     #[ORM\Column(name'ip'type'string'length128)]
  25.     protected string $ip;
  26.     /**
  27.      * Binary representation of the first ip address in range
  28.      *
  29.      * @internal Don't use it outside of entity or repository queries.
  30.      */
  31.     #[ORM\Column(name'ip_range_first'type'binary'length16nullabletrue)]
  32.     private $ipRangeFirst;
  33.     /**
  34.      * Binary representation of the last ip address in range
  35.      *
  36.      * @internal Don't use it outside of entity or repository queries.
  37.      */
  38.     #[ORM\Column(name'ip_range_last'type'binary'length16nullabletrue)]
  39.     private $ipRangeLast;
  40.     /**
  41.      * Ip range subnet for lookup order from large subnet to smaller
  42.      *
  43.      * @internal Don't use it outside of entity or repository queries.
  44.      */
  45.     #[ORM\Column(name'ip_range_subnet'type'smallint'nullabletrue)]
  46.     private ?int $ipRangeSubnet;
  47.     /** @var IpAddressDailyCommentBan[] */
  48.     #[ORM\OneToMany(targetEntityIpAddressDailyCommentBan::class, mappedBy'ipAddress'cascade: ['all'], orphanRemovaltrue)]
  49.     private Collection $dailyCommentBans;
  50.     /** @var IpAddressPermanentCommentBan[] */
  51.     #[ORM\OneToMany(targetEntityIpAddressPermanentCommentBan::class, mappedBy'ipAddress'cascade: ['all'], orphanRemovaltrue)]
  52.     protected Collection $permanentCommentBans;
  53.     /** @var CommentByCustomer[] */
  54.     #[ORM\OneToMany(targetEntityCommentByCustomer::class, mappedBy'ipAddress')]
  55.     private Collection $profileComments;
  56.     /** @var \App\Entity\Saloon\Comment\CommentByCustomer[] */
  57.     #[ORM\OneToMany(targetEntity\App\Entity\Saloon\Comment\CommentByCustomer::class, mappedBy'ipAddress')]
  58.     private Collection $saloonComments;
  59.     public static function normalize(string $rawbool $withSubnet true): string
  60.     {
  61.         $singleAddressSubnet 32;
  62.         // Определяем маску подсети: 172.22.19.1/19, 172.22.10.5/32
  63.         if (str_contains($raw'/')) {
  64.             [$ip$subnet] = explode('/'$raw2);
  65.             $subnet filter_var($subnetFILTER_VALIDATE_INT, ['options' => [
  66.                 'default' => $singleAddressSubnet,
  67.                 'min_range' => 0,
  68.                 'max_range' => $singleAddressSubnet,
  69.             ]]);
  70.         } else {
  71.             $ip $raw;
  72.             $subnet $singleAddressSubnet;
  73.         }
  74.         // Если подсеть была указана в виде маски: 172.22., 172.22.*, 172.22.10.*
  75.         $ipParts preg_split('/\./'$ip, -1PREG_SPLIT_NO_EMPTY);
  76.         for ($pad count($ipParts); $pad 0$pad--) {
  77.             $ipParts[] = '*';
  78.         }
  79.         for ($i 3$i >= 0$i--) {
  80.             if ('*' === $ipParts[$i]) {
  81.                 $ipParts[$i] = '0';
  82.                 $subnet $i 8;
  83.             }
  84.         }
  85.         $normalized implode('.'$ipParts);
  86.         if ($withSubnet) {
  87.             $normalized .= '/'.$subnet;
  88.         }
  89.         return $normalized;
  90.     }
  91.     public function __construct(string $ip null)
  92.     {
  93.         if (null !== $ip) {
  94.             $this->setIp($ip);
  95.         }
  96.         $this->dailyCommentBans = new ArrayCollection();
  97.         $this->permanentCommentBans = new ArrayCollection();
  98.         $this->profileComments = new ArrayCollection();
  99.         $this->saloonComments = new ArrayCollection();
  100.     }
  101.     public function setIp(string $raw): void
  102.     {
  103.         $normalized self::normalize($rawtrue);
  104.         $network Network::parse($normalized);
  105.         $range $network->getHosts();
  106.         $this->ip $normalized;
  107.         $this->ipRangeFirst $range->getFirstIP()->inAddr();
  108.         $this->ipRangeLast $range->getLastIP()->inAddr();
  109.         $this->ipRangeSubnet $network->getPrefixLength();
  110.     }
  111.     public function getId(): ?int
  112.     {
  113.         return $this->id;
  114.     }
  115.     public function getIp(): ?string
  116.     {
  117.         return $this->ip;
  118.     }
  119.     public function getTodayCommentCount(): int
  120.     {
  121.         return $this->getTodayProfileCommentCount() + $this->getTodaySaloonCommentCount();
  122.     }
  123.     public function getTodaySaloonCommentCount(): int
  124.     {
  125.         $criteria Criteria::create()
  126.             ->where(Criteria::expr()->gte("createdAt"CarbonImmutable::today()));
  127.         return $this->saloonComments->matching($criteria)->count();
  128.     }
  129.     public function getTodayProfileCommentCount(): int
  130.     {
  131.         $criteria Criteria::create()
  132.             ->where(Criteria::expr()->gte("createdAt"CarbonImmutable::today()));
  133.         return $this->profileComments->matching($criteria)->count();
  134.     }
  135.     public function getProfileComments(): Collection
  136.     {
  137.         return $this->profileComments;
  138.     }
  139.     public function getSaloonComments(): Collection
  140.     {
  141.         return $this->saloonComments;
  142.     }
  143.     public function getDailyCommentBansCount(): int
  144.     {
  145.         return $this->dailyCommentBans->count();
  146.     }
  147.     public function getActiveDailyCommentBan(): ?IpAddressDailyCommentBan
  148.     {
  149.         $criteria Criteria::create()
  150.             ->where(Criteria::expr()->gte("date"CarbonImmutable::today()))
  151.             ->andWhere(Criteria::expr()->eq("isReset"false));
  152.         $result $this->dailyCommentBans->matching($criteria);
  153.         return $result->count() ? $result->first() : null;
  154.     }
  155.     public function getTodayDailyCommentBansCount(): int
  156.     {
  157.         $criteria Criteria::create()
  158.             ->where(Criteria::expr()->gte("date"CarbonImmutable::today()));
  159.         return $this->dailyCommentBans->matching($criteria)->count();
  160.     }
  161.     public function setDailyCommentBan(): void
  162.     {
  163.         if(null !== $this->getActiveDailyCommentBan()) {
  164.             throw new \DomainException('Daily ban for today for this IP already set.');
  165.         }
  166.         $this->dailyCommentBans->add(new IpAddressDailyCommentBan($thisCarbonImmutable::now()));
  167.     }
  168.     public function getPermanentCommentBansCount(): int
  169.     {
  170.         return $this->permanentCommentBans->count();
  171.     }
  172.     public function getActivePermanentCommentBan(): ?IpAddressPermanentCommentBan
  173.     {
  174.         $criteria Criteria::create()
  175.             ->andWhere(Criteria::expr()->eq("isReset"false));
  176.         $result $this->permanentCommentBans->matching($criteria);
  177.         return $result->count() ? $result->first() : null;
  178.     }
  179.     public function getPermanentDailyCommentBans(): Collection
  180.     {
  181.         $criteria Criteria::create()
  182.             ->where(Criteria::expr()->gte("date"CarbonImmutable::today()));
  183.         return $this->permanentCommentBans->matching($criteria);
  184.     }
  185.     public function setPermanentCommentBan(): void
  186.     {
  187.         if(null !== $this->getActivePermanentCommentBan()) {
  188.             throw new \DomainException('Permanent ban for this IP already set.');
  189.         }
  190.         $this->permanentCommentBans->add(new IpAddressPermanentCommentBan($thisCarbonImmutable::now()));
  191.     }
  192.     /**
  193.      * @inheritDoc
  194.      */
  195.     public function __toString(): string
  196.     {
  197.         return (string) $this->ip;
  198.     }
  199. }