Completed
Push — master ( 1f2836...52bb47 )
by Mark
10s
created

src/CrawlerDetect.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Crawlers;
15
use Jaybizzle\CrawlerDetect\Fixtures\Exclusions;
16
use Jaybizzle\CrawlerDetect\Fixtures\Headers;
17
18
class CrawlerDetect
19
{
20
    /**
21
     * The user agent.
22
     *
23
     * @var null
24
     */
25
    protected $userAgent = null;
26
27
    /**
28
     * Headers that contain a user agent.
29
     *
30
     * @var array
31
     */
32
    protected $httpHeaders = array();
33
34
    /**
35
     * Store regex matches.
36
     *
37
     * @var array
38
     */
39
    protected $matches = array();
40
41
    /**
42
     * Crawlers object.
43
     *
44
     * @var \Jaybizzle\CrawlerDetect\Fixtures\Crawlers
45
     */
46
    protected $crawlers;
47
48
    /**
49
     * Exclusions object.
50
     *
51
     * @var \Jaybizzle\CrawlerDetect\Fixtures\Exclusions
52
     */
53
    protected $exclusions;
54
55
    /**
56
     * Headers object.
57
     *
58
     * @var \Jaybizzle\CrawlerDetect\Fixtures\Headers
59
     */
60
    protected $uaHttpHeaders;
61
62
    /**
63
     * Class constructor.
64
     */
65
    public function __construct(array $headers = null, $userAgent = null)
66
    {
67
        $this->crawlers = new Crawlers();
68
        $this->exclusions = new Exclusions();
69
        $this->uaHttpHeaders = new Headers();
70
71
        $this->setHttpHeaders($headers);
72
        $this->setUserAgent($userAgent);
73
    }
74
75
    /**
76
     * Set HTTP headers.
77
     *
78
     * @param array $httpHeaders
79
     */
80
    public function setHttpHeaders($httpHeaders = null)
0 ignored issues
show
setHttpHeaders uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
81
    {
82
        // use global _SERVER if $httpHeaders aren't defined
83
        if (!is_array($httpHeaders) || !count($httpHeaders)) {
84
            $httpHeaders = $_SERVER;
85
        }
86
        // clear existing headers
87
        $this->httpHeaders = array();
88
        // Only save HTTP headers. In PHP land, that means only _SERVER vars that
89
        // start with HTTP_.
90
        foreach ($httpHeaders as $key => $value) {
91
            if (substr($key, 0, 5) === 'HTTP_') {
92
                $this->httpHeaders[$key] = $value;
93
            }
94
        }
95
    }
96
97
    /**
98
     * Return user agent headers.
99
     *
100
     * @return array
101
     */
102
    public function getUaHttpHeaders()
103
    {
104
        return $this->uaHttpHeaders->getAll();
105
    }
106
107
    /**
108
     * Set the user agent.
109
     *
110
     * @param string $userAgent
111
     */
112
    public function setUserAgent($userAgent = null)
113
    {
114
        if (false === empty($userAgent)) {
115
            return $this->userAgent = $userAgent;
116
        } else {
117
            $this->userAgent = null;
118
            foreach ($this->getUaHttpHeaders() as $altHeader) {
119
                if (false === empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow.
120
                    $this->userAgent .= $this->httpHeaders[$altHeader].' ';
121
                }
122
            }
123
124
            return $this->userAgent = (!empty($this->userAgent) ? trim($this->userAgent) : null);
125
        }
126
    }
127
128
    /**
129
     * Build the user agent regex.
130
     *
131
     * @return string
132
     */
133
    public function getRegex()
134
    {
135
        return '('.implode('|', $this->crawlers->getAll()).')';
136
    }
137
138
    /**
139
     * Build the replacement regex.
140
     *
141
     * @return string
142
     */
143
    public function getExclusions()
144
    {
145
        return '('.implode('|', $this->exclusions->getAll()).')';
146
    }
147
148
    /**
149
     * Check user agent string against the regex.
150
     *
151
     * @param string $userAgent
152
     *
153
     * @return bool
154
     */
155
    public function isCrawler($userAgent = null)
156
    {
157
        $agent = is_null($userAgent) ? $this->userAgent : $userAgent;
158
159
        $agent = preg_replace('/'.$this->getExclusions().'/i', '', $agent);
160
161
        if (strlen(trim($agent)) == 0) {
162
            return false;
163
        } else {
164
            $result = preg_match('/'.$this->getRegex().'/i', trim($agent), $matches);
165
        }
166
167
        if ($matches) {
0 ignored issues
show
Bug Best Practice introduced by Mark Beech
The expression $matches of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
168
            $this->matches = $matches;
169
        }
170
171
        return (bool) $result;
172
    }
173
174
    /**
175
     * Return the matches.
176
     *
177
     * @return string
178
     */
179
    public function getMatches()
180
    {
181
        return $this->matches[0];
182
    }
183
}
184