• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

codeigniter4 / CodeIgniter4 / 37986190232

09 Oct 2026 08:19PM UTC coverage: 50.703% (-39.5%) from 90.183%
37986190232

Pull #10606

github

web-flow
Merge 2cebb1efa into 7822cde17
Pull Request #10606: fix: refresh REQUEST after URI GET normalization

17 of 30 new or added lines in 2 files covered. (56.67%)

10012 existing lines in 288 files now uncovered.

12871 of 25385 relevant lines covered (50.7%)

87.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

31.76
/system/HTTP/UserAgent.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of CodeIgniter 4 framework.
7
 *
8
 * (c) CodeIgniter Foundation <admin@codeigniter.com>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace CodeIgniter\HTTP;
15

16
use Config\UserAgents;
17
use Stringable;
18

19
/**
20
 * Abstraction for an HTTP user agent
21
 *
22
 * @see \CodeIgniter\HTTP\UserAgentTest
23
 */
24
class UserAgent implements Stringable
25
{
26
    /**
27
     * Current user-agent
28
     *
29
     * @var string
30
     */
31
    protected $agent = '';
32

33
    /**
34
     * Flag for if the user-agent belongs to a browser
35
     *
36
     * @var bool
37
     */
38
    protected $isBrowser = false;
39

40
    /**
41
     * Flag for if the user-agent is a robot
42
     *
43
     * @var bool
44
     */
45
    protected $isRobot = false;
46

47
    /**
48
     * Flag for if the user-agent is a mobile browser
49
     *
50
     * @var bool
51
     */
52
    protected $isMobile = false;
53

54
    /**
55
     * Holds the config file contents.
56
     *
57
     * @var UserAgents
58
     */
59
    protected $config;
60

61
    /**
62
     * Current user-agent platform
63
     *
64
     * @var string
65
     */
66
    protected $platform = '';
67

68
    /**
69
     * Current user-agent browser
70
     *
71
     * @var string
72
     */
73
    protected $browser = '';
74

75
    /**
76
     * Current user-agent version
77
     *
78
     * @var string
79
     */
80
    protected $version = '';
81

82
    /**
83
     * Current user-agent mobile name
84
     *
85
     * @var string
86
     */
87
    protected $mobile = '';
88

89
    /**
90
     * Current user-agent robot name
91
     *
92
     * @var string
93
     */
94
    protected $robot = '';
95

96
    /**
97
     * HTTP Referer
98
     *
99
     * @var bool|string|null
100
     */
101
    protected $referrer;
102

103
    /**
104
     * Constructor
105
     *
106
     * Sets the User Agent and runs the compilation routine
107
     */
108
    public function __construct(?UserAgents $config = null)
109
    {
110
        $this->config = $config ?? config(UserAgents::class);
648 ✔
111

112
        $userAgent = service('superglobals')->server('HTTP_USER_AGENT');
648 ✔
113

114
        if ($userAgent !== null) {
648 ✔
115
            $this->agent = trim($userAgent);
1 ✔
116
            $this->compileData();
1 ✔
117
        }
118
    }
119

120
    /**
121
     * Is Browser
122
     */
123
    public function isBrowser(?string $key = null): bool
124
    {
UNCOV
125
        if (! $this->isBrowser) {
×
UNCOV
126
            return false;
×
127
        }
128

129
        // No need to be specific, it's a browser
UNCOV
130
        if ((string) $key === '') {
×
UNCOV
131
            return true;
×
132
        }
133

134
        // Check for a specific browser
UNCOV
135
        return isset($this->config->browsers[$key]) && $this->browser === $this->config->browsers[$key];
×
136
    }
137

138
    /**
139
     * Is Robot
140
     */
141
    public function isRobot(?string $key = null): bool
142
    {
UNCOV
143
        if (! $this->isRobot) {
×
UNCOV
144
            return false;
×
145
        }
146

147
        // No need to be specific, it's a robot
UNCOV
148
        if ((string) $key === '') {
×
UNCOV
149
            return true;
×
150
        }
151

152
        // Check for a specific robot
UNCOV
153
        return isset($this->config->robots[$key]) && $this->robot === $this->config->robots[$key];
×
154
    }
155

156
    /**
157
     * Is Mobile
158
     */
159
    public function isMobile(?string $key = null): bool
160
    {
UNCOV
161
        if (! $this->isMobile) {
×
UNCOV
162
            return false;
×
163
        }
164

165
        // No need to be specific, it's a mobile
UNCOV
166
        if ((string) $key === '') {
×
UNCOV
167
            return true;
×
168
        }
169

170
        // Check for a specific robot
UNCOV
171
        return isset($this->config->mobiles[$key]) && $this->mobile === $this->config->mobiles[$key];
×
172
    }
173

174
    /**
175
     * Is this a referral from another site?
176
     */
177
    public function isReferral(): bool
178
    {
UNCOV
179
        if (! isset($this->referrer)) {
×
UNCOV
180
            $referer = service('superglobals')->server('HTTP_REFERER');
×
UNCOV
181
            if ($referer === null || $referer === '') {
×
UNCOV
182
                $this->referrer = false;
×
183
            } else {
UNCOV
184
                $refererHost = @parse_url($referer, PHP_URL_HOST);
×
UNCOV
185
                $ownHost     = parse_url(\base_url(), PHP_URL_HOST);
×
186

UNCOV
187
                $this->referrer = ($refererHost && $refererHost !== $ownHost);
×
188
            }
189
        }
190

UNCOV
191
        return $this->referrer;
×
192
    }
193

194
    /**
195
     * Agent String
196
     */
197
    public function getAgentString(): string
198
    {
199
        return $this->agent;
1 ✔
200
    }
201

202
    /**
203
     * Get Platform
204
     */
205
    public function getPlatform(): string
206
    {
UNCOV
207
        return $this->platform;
×
208
    }
209

210
    /**
211
     * Get Browser Name
212
     */
213
    public function getBrowser(): string
214
    {
UNCOV
215
        return $this->browser;
×
216
    }
217

218
    /**
219
     * Get the Browser Version
220
     */
221
    public function getVersion(): string
222
    {
UNCOV
223
        return $this->version;
×
224
    }
225

226
    /**
227
     * Get The Robot Name
228
     */
229
    public function getRobot(): string
230
    {
UNCOV
231
        return $this->robot;
×
232
    }
233

234
    /**
235
     * Get the Mobile Device
236
     */
237
    public function getMobile(): string
238
    {
UNCOV
239
        return $this->mobile;
×
240
    }
241

242
    /**
243
     * Get the referrer
244
     */
245
    public function getReferrer(): string
246
    {
UNCOV
247
        $referrer = service('superglobals')->server('HTTP_REFERER');
×
248

UNCOV
249
        return $referrer === null ? '' : trim($referrer);
×
250
    }
251

252
    /**
253
     * Parse a custom user-agent string
254
     *
255
     * @return void
256
     */
257
    public function parse(string $string)
258
    {
259
        // Reset values
UNCOV
260
        $this->isBrowser = false;
×
UNCOV
261
        $this->isRobot   = false;
×
UNCOV
262
        $this->isMobile  = false;
×
UNCOV
263
        $this->browser   = '';
×
UNCOV
264
        $this->version   = '';
×
UNCOV
265
        $this->mobile    = '';
×
UNCOV
266
        $this->robot     = '';
×
267

268
        // Set the new user-agent string and parse it, unless empty
UNCOV
269
        $this->agent = $string;
×
270

UNCOV
271
        if ($string !== '') {
×
UNCOV
272
            $this->compileData();
×
273
        }
274
    }
275

276
    /**
277
     * Compile the User Agent Data
278
     *
279
     * @return void
280
     */
281
    protected function compileData()
282
    {
283
        $this->setPlatform();
1 ✔
284

285
        foreach (['setRobot', 'setBrowser', 'setMobile'] as $function) {
1 ✔
286
            if ($this->{$function}()) {
1 ✔
UNCOV
287
                break;
×
288
            }
289
        }
290
    }
291

292
    /**
293
     * Set the Platform
294
     */
295
    protected function setPlatform(): bool
296
    {
297
        if (is_array($this->config->platforms) && $this->config->platforms !== []) {
1 ✔
298
            foreach ($this->config->platforms as $key => $val) {
1 ✔
299
                if (preg_match('|' . preg_quote($key, '|') . '|i', $this->agent)) {
1 ✔
UNCOV
300
                    $this->platform = $val;
×
301

UNCOV
302
                    return true;
×
303
                }
304
            }
305
        }
306

307
        $this->platform = 'Unknown Platform';
1 ✔
308

309
        return false;
1 ✔
310
    }
311

312
    /**
313
     * Set the Browser
314
     */
315
    protected function setBrowser(): bool
316
    {
317
        if (is_array($this->config->browsers) && $this->config->browsers !== []) {
1 ✔
318
            foreach ($this->config->browsers as $key => $val) {
1 ✔
319
                if (preg_match('|' . $key . '.*?([0-9\.]+)|i', $this->agent, $match)) {
1 ✔
UNCOV
320
                    $version = $match[1];
×
321

322
                    // Safari's browser version is reported in the Version token.
UNCOV
323
                    if ($val === 'Safari' && preg_match('|Version/([0-9\.]+).*?Safari|i', $this->agent, $safariMatch)) {
×
UNCOV
324
                        $version = $safariMatch[1];
×
325
                    }
326

UNCOV
327
                    $this->isBrowser = true;
×
UNCOV
328
                    $this->version   = $version;
×
UNCOV
329
                    $this->browser   = $val;
×
UNCOV
330
                    $this->setMobile();
×
331

UNCOV
332
                    return true;
×
333
                }
334
            }
335
        }
336

337
        return false;
1 ✔
338
    }
339

340
    /**
341
     * Set the Robot
342
     */
343
    protected function setRobot(): bool
344
    {
345
        if (is_array($this->config->robots) && $this->config->robots !== []) {
1 ✔
346
            foreach ($this->config->robots as $key => $val) {
1 ✔
347
                if (preg_match('|' . preg_quote($key, '|') . '|i', $this->agent)) {
1 ✔
UNCOV
348
                    $this->isRobot = true;
×
UNCOV
349
                    $this->robot   = $val;
×
UNCOV
350
                    $this->setMobile();
×
351

UNCOV
352
                    return true;
×
353
                }
354
            }
355
        }
356

357
        return false;
1 ✔
358
    }
359

360
    /**
361
     * Set the Mobile Device
362
     */
363
    protected function setMobile(): bool
364
    {
365
        if (is_array($this->config->mobiles) && $this->config->mobiles !== []) {
1 ✔
366
            foreach ($this->config->mobiles as $key => $val) {
1 ✔
367
                if (false !== (stripos($this->agent, $key))) {
1 ✔
UNCOV
368
                    $this->isMobile = true;
×
UNCOV
369
                    $this->mobile   = $val;
×
370

UNCOV
371
                    return true;
×
372
                }
373
            }
374
        }
375

376
        return false;
1 ✔
377
    }
378

379
    /**
380
     * Outputs the original Agent String when cast as a string.
381
     */
382
    public function __toString(): string
383
    {
384
        return $this->getAgentString();
1 ✔
385
    }
386
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc