Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
urlchecker.php
1<?php
2namespace Bitrix\Landing;
3
9
14{
15 private const EXTERNAL_CHECKER_URL_LOAD_URL = 'https://www.virustotal.com/api/v3/urls';
16 private const EXTERNAL_CHECKER_URL_GET_ANALYSE = 'https://www.virustotal.com/api/v3/analyses/';
17
18 private const STATUS_KEY_GOOD = 'harmless';
19 private const STATUS_KEY_AVERAGE = 'suspicious';
20 private const STATUS_KEY_BAD = 'malicious';
21
22 private const AVERAGE_STATUS_PERCENT = 33;
23
24 private $apiKey;
25 private $hostUrl;
26
33 public function __construct(string $apiKey, ?string $hostUrl = null)
34 {
35 $this->apiKey = $apiKey;
36 $this->hostUrl = $hostUrl;
37 if ($this->hostUrl)
38 {
39 $this->hostUrl = mb_strtolower(trim($this->hostUrl));
40 }
41 }
42
50 protected function getUrlStatus(string $url): ?string
51 {
52 try
53 {
54 $http = new HttpClient;
55 $http->setHeader('x-apikey', $this->apiKey);
56 $res = Json::decode($http->post(self::EXTERNAL_CHECKER_URL_LOAD_URL, [
57 'url' => $url,
58 ]));
59 if (!isset($res['error']) && $res['data'] && $res['data']['id'])
60 {
61 $resAnalysis = Json::decode($http->get(self::EXTERNAL_CHECKER_URL_GET_ANALYSE . $res['data']['id']));
62 if (isset($resAnalysis['error']))
63 {
64 // todo: set VT error
65 return $res['error']['status'];
66 }
67 $stats = [
68 self::STATUS_KEY_GOOD => $resAnalysis['data']['attributes']['stats'][self::STATUS_KEY_GOOD],
69 self::STATUS_KEY_AVERAGE => $resAnalysis['data']['attributes']['stats'][self::STATUS_KEY_AVERAGE],
70 self::STATUS_KEY_BAD => $resAnalysis['data']['attributes']['stats'][self::STATUS_KEY_BAD],
71 ];
72
73 // check stats
74 $total = $stats[self::STATUS_KEY_GOOD] + $stats[self::STATUS_KEY_AVERAGE] + $stats[self::STATUS_KEY_BAD];
75 if (
76 $stats[self::STATUS_KEY_BAD] === 0
77 && $stats[self::STATUS_KEY_AVERAGE] <= $total * self::AVERAGE_STATUS_PERCENT * 0.01
78 )
79 {
80 return null;
81 }
82
83 return
84 self::STATUS_KEY_GOOD . ':' . $stats[self::STATUS_KEY_GOOD]
85 . '_' . self::STATUS_KEY_AVERAGE . ':' . $stats[self::STATUS_KEY_AVERAGE]
86 . '_' . self::STATUS_KEY_BAD . ':' . $stats[self::STATUS_KEY_BAD];
87 }
88 }
89 catch (\Exception $e){}
90
91 return null;
92 }
93
100 protected function saveHost(int $statusId): void
101 {
102 if (!$this->hostUrl)
103 {
104 return;
105 }
106 $res = UrlCheckerHostTable::getList([
107 'select' => [
108 'ID'
109 ],
110 'filter' => [
111 'STATUS_ID' => $statusId,
112 '=HOST' => $this->hostUrl
113 ],
114 'limit' => 1
115 ]);
116 if (!$res->fetch())
117 {
118 UrlCheckerHostTable::add([
119 'STATUS_ID' => $statusId,
120 'HOST' => $this->hostUrl
121 ])->isSuccess();
122 }
123 }
124
132 public function check(string $url): bool
133 {
134 $url = mb_strtolower($url);
135 $urlMd5 = md5(explode('//', $url)[1] ?? $url);
136 $urlParts = parse_url($url);
137 $domain = $urlParts['host'] ?? null;
138
139 if (!$domain)
140 {
141 return true;
142 }
143
144 // check domain in white list
145 $res = UrlCheckerWhitelistTable::getList([
146 'filter' => [
147 '=DOMAIN' => $domain
148 ],
149 'limit' => 1
150 ]);
151 if ($res->fetch())
152 {
153 return true;
154 }
155
156 // check exists url
157 $res = UrlCheckerStatusTable::getList([
158 'select' => [
159 'ID', 'STATUS'
160 ],
161 'filter' => [
162 '=HASH' => $urlMd5
163 ]
164 ]);
165 if ($row = $res->fetch())
166 {
167 if ($row['STATUS'])
168 {
169 $this->saveHost($row['ID']);
170 }
171 return !$row['STATUS'];
172 }
173
174 // new check
175 $status = $this->getUrlStatus($url);
176 $res = UrlCheckerStatusTable::add([
177 'STATUS' => $status,
178 'HASH' => $urlMd5,
179 'URL' => $url
180 ]);
181 // save host if status is bad
182 if ($res->isSuccess() && $status)
183 {
184 $this->saveHost($res->getId());
185 }
186
187 return $status === null;
188 }
189}
__construct(string $apiKey, ?string $hostUrl=null)
setHeader($name, $value, $replace=true)