PluginProbe
WebberZone Top 10 — Popular Posts / 4.4.1
WebberZone Top 10 — Popular Posts v4.4.1
4.5.1 4.5.0 4.4.3 4.4.2 4.4.1 4.4.0 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 trunk 1.0 1.0.1 1.1 1.2 1.3 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 1.6.1 All 117 releases
top-10 / vendor / jaybizzle / crawler-detect / src / CrawlerDetect.php

CrawlerDetect.php in WebberZone Top 10 — Popular Posts 4.4.1, at vendor/jaybizzle/crawler-detect/src/CrawlerDetect.php

245 lines 5.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of Crawler Detect - the web crawler detection library.
5 *
6 * (c) Mark Beech <[email protected]>
7 *
8 * This source file is subject to the MIT license that is bundled
9 * with this source code in the file LICENSE.
10 */
11
12 namespace Jaybizzle\CrawlerDetect;
13
14 use Jaybizzle\CrawlerDetect\Fixtures\AbstractProvider;
15 use Jaybizzle\CrawlerDetect\Fixtures\Crawlers;
16 use Jaybizzle\CrawlerDetect\Fixtures\Exclusions;
17 use Jaybizzle\CrawlerDetect\Fixtures\Headers;
18
19 class CrawlerDetect
20 {
21 /**
22 * The user agent.
23 *
24 * @var string|null
25 */
26 protected $userAgent;
27
28 /**
29 * Headers that contain a user agent.
30 *
31 * @var array
32 */
33 protected $httpHeaders = [];
34
35 /**
36 * Store regex matches.
37 *
38 * @var array
39 */
40 protected $matches = [];
41
42 /**
43 * Crawlers object.
44 *
45 * @var \Jaybizzle\CrawlerDetect\Fixtures\Crawlers
46 */
47 protected $crawlers;
48
49 /**
50 * Exclusions object.
51 *
52 * @var \Jaybizzle\CrawlerDetect\Fixtures\Exclusions
53 */
54 protected $exclusions;
55
56 /**
57 * Headers object.
58 *
59 * @var \Jaybizzle\CrawlerDetect\Fixtures\Headers
60 */
61 protected $uaHttpHeaders;
62
63 /**
64 * The compiled regex string.
65 *
66 * @var string
67 */
68 protected $compiledRegex;
69
70 /**
71 * The compiled exclusions regex string.
72 *
73 * @var string
74 */
75 protected $compiledExclusions;
76
77 /**
78 * Cache of compiled regex strings keyed by fixture class name, shared
79 * across instances so per-request `new CrawlerDetect` calls don't
80 * re-implode the (~1500-entry) pattern list each time.
81 *
82 * @var array<string, string>
83 */
84 protected static $compileCache = [];
85
86 /**
87 * Class constructor.
88 */
89 public function __construct(?array $headers = null, $userAgent = null)
90 {
91 $this->crawlers = new Crawlers;
92 $this->exclusions = new Exclusions;
93 $this->uaHttpHeaders = new Headers;
94
95 $this->compiledRegex = $this->compileFixtureRegex($this->crawlers);
96 $this->compiledExclusions = $this->compileFixtureRegex($this->exclusions);
97
98 $this->setHttpHeaders($headers);
99 $this->setUserAgent($userAgent);
100 }
101
102 /**
103 * Compile and memoize the regex for a fixture provider.
104 *
105 * The pattern list is a fixed class property, so the class name is a
106 * sufficient cache key — cheaper than hashing the patterns themselves.
107 *
108 * @return string
109 */
110 protected function compileFixtureRegex(AbstractProvider $fixture)
111 {
112 $class = get_class($fixture);
113
114 if (! isset(self::$compileCache[$class])) {
115 self::$compileCache[$class] = $this->compileRegex($fixture->getAll());
116 }
117
118 return self::$compileCache[$class];
119 }
120
121 /**
122 * Compile the regex patterns into one regex string.
123 *
124 * A non-capturing group is used because callers only need the full
125 * match (preg_match's $matches[0]), not a back-reference.
126 *
127 * @param array $patterns
128 * @return string
129 */
130 public function compileRegex($patterns)
131 {
132 return '(?:'.implode('|', $patterns).')';
133 }
134
135 /**
136 * Set HTTP headers.
137 *
138 * @param array|null $httpHeaders
139 */
140 public function setHttpHeaders($httpHeaders = null)
141 {
142 // Use global _SERVER if $httpHeaders aren't defined.
143 if (! is_array($httpHeaders) || ! count($httpHeaders)) {
144 $httpHeaders = $_SERVER;
145 }
146
147 // Clear existing headers.
148 $this->httpHeaders = [];
149
150 // Only save HTTP headers. In PHP land, that means
151 // only _SERVER vars that start with HTTP_.
152 foreach ($httpHeaders as $key => $value) {
153 if (strpos($key, 'HTTP_') === 0) {
154 $this->httpHeaders[$key] = $value;
155 }
156 }
157 }
158
159 /**
160 * Return user agent headers.
161 *
162 * @return array
163 */
164 public function getUaHttpHeaders()
165 {
166 return $this->uaHttpHeaders->getAll();
167 }
168
169 /**
170 * Set the user agent.
171 *
172 * @param string|null $userAgent
173 */
174 public function setUserAgent($userAgent = null)
175 {
176 if (is_null($userAgent)) {
177 $userAgent = '';
178
179 foreach ($this->getUaHttpHeaders() as $altHeader) {
180 if (isset($this->httpHeaders[$altHeader])) {
181 $userAgent .= $this->httpHeaders[$altHeader].' ';
182 }
183 }
184
185 // If no headers were found, keep it as null.
186 if ($userAgent === '') {
187 $userAgent = null;
188 }
189 }
190
191 return $this->userAgent = $userAgent;
192 }
193
194 /**
195 * Check user agent string against the regex.
196 *
197 * @param string|null $userAgent
198 * @return bool
199 */
200 public function isCrawler($userAgent = null)
201 {
202 $this->matches = [];
203
204 $agent = preg_replace(
205 "/{$this->compiledExclusions}/i",
206 '',
207 $userAgent ?: $this->userAgent ?: ''
208 );
209
210 if ($agent === null || trim($agent) === '') {
211 return false;
212 }
213
214 $agent = trim($agent);
215
216 $result = preg_match("/{$this->compiledRegex}/i", $agent, $this->matches);
217
218 if ($result === false) {
219 $this->matches = [];
220
221 return false;
222 }
223
224 return (bool) $result;
225 }
226
227 /**
228 * Return the matches.
229 *
230 * @return string|null
231 */
232 public function getMatches()
233 {
234 return isset($this->matches[0]) ? $this->matches[0] : null;
235 }
236
237 /**
238 * @return string|null
239 */
240 public function getUserAgent()
241 {
242 return $this->userAgent;
243 }
244 }
245