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

codeigniter4 / CodeIgniter4 / 26717872894

31 May 2026 04:19PM UTC coverage: 88.556% (+0.08%) from 88.475%
26717872894

Pull #10242

github

web-flow
Merge 47dc3835f into 2ef1571f5
Pull Request #10242: feat: add immutable URI query variable helpers

7 of 7 new or added lines in 1 file covered. (100.0%)

155 existing lines in 9 files now uncovered.

24267 of 27403 relevant lines covered (88.56%)

223.65 hits per line

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

94.57
/system/HTTP/IncomingRequest.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 CodeIgniter\Exceptions\InvalidArgumentException;
17
use CodeIgniter\HTTP\Exceptions\HTTPException;
18
use CodeIgniter\HTTP\Files\FileCollection;
19
use CodeIgniter\HTTP\Files\UploadedFile;
20
use Config\App;
21
use Config\Services;
22
use Locale;
23
use stdClass;
24

25
/**
26
 * Class IncomingRequest
27
 *
28
 * Represents an incoming, server-side HTTP request.
29
 *
30
 * Per the HTTP specification, this interface includes properties for
31
 * each of the following:
32
 *
33
 * - Protocol version
34
 * - HTTP method
35
 * - URI
36
 * - Headers
37
 * - Message body
38
 *
39
 * Additionally, it encapsulates all data as it has arrived to the
40
 * application from the CGI and/or PHP environment, including:
41
 *
42
 * - The values represented in $_SERVER.
43
 * - Any cookies provided (generally via $_COOKIE)
44
 * - Query string arguments (generally via $_GET, or as parsed via parse_str())
45
 * - Upload files, if any (as represented by $_FILES)
46
 * - Deserialized body binds (generally from $_POST)
47
 *
48
 * @see \CodeIgniter\HTTP\IncomingRequestTest
49
 */
50
class IncomingRequest extends Request
51
{
52
    /**
53
     * The URI for this request.
54
     *
55
     * Note: This WILL NOT match the actual URL in the browser since for
56
     * everything this cares about (and the router, etc) is the portion
57
     * AFTER the baseURL. So, if hosted in a sub-folder this will
58
     * appear different than actual URI path. If you need that use getPath().
59
     *
60
     * @var URI
61
     */
62
    protected $uri;
63

64
    /**
65
     * The detected URI path (relative to the baseURL).
66
     *
67
     * Note: current_url() uses this to build its URI,
68
     * so this becomes the source for the "current URL"
69
     * when working with the share request instance.
70
     *
71
     * @var string|null
72
     */
73
    protected $path;
74

75
    /**
76
     * File collection
77
     *
78
     * @var FileCollection|null
79
     */
80
    protected $files;
81

82
    /**
83
     * Negotiator
84
     *
85
     * @var Negotiate|null
86
     */
87
    protected $negotiator;
88

89
    /**
90
     * The default Locale this request
91
     * should operate under.
92
     *
93
     * @var string
94
     */
95
    protected $defaultLocale;
96

97
    /**
98
     * The current locale of the application.
99
     * Default value is set in app/Config/App.php
100
     *
101
     * @var string
102
     */
103
    protected $locale;
104

105
    /**
106
     * Stores the valid locale codes.
107
     *
108
     * @var array
109
     */
110
    protected $validLocales = [];
111

112
    /**
113
     * Holds the old data from a redirect.
114
     *
115
     * @var array
116
     */
117
    protected $oldInput = [];
118

119
    /**
120
     * The user agent this request is from.
121
     *
122
     * @var UserAgent
123
     */
124
    protected $userAgent;
125

126
    /**
127
     * Typed input data selector.
128
     */
129
    protected ?RequestInput $input = null;
130

131
    /**
132
     * Constructor
133
     *
134
     * @param App         $config
135
     * @param string|null $body
136
     */
137
    public function __construct($config, ?URI $uri = null, $body = 'php://input', ?UserAgent $userAgent = null)
138
    {
139
        if (! $uri instanceof URI || ! $userAgent instanceof UserAgent) {
3,453✔
UNCOV
140
            throw new InvalidArgumentException('You must supply the parameters: uri, userAgent.');
×
141
        }
142

143
        $this->populateHeaders();
3,453✔
144

145
        if (
146
            $body === 'php://input'
3,453✔
147
            // php://input is not available with enctype="multipart/form-data".
148
            // See https://www.php.net/manual/en/wrappers.php.php#wrappers.php.input
149
            && ! str_contains($this->getHeaderLine('Content-Type'), 'multipart/form-data')
3,453✔
150
            && (int) $this->getHeaderLine('Content-Length') <= $this->getPostMaxSize()
3,453✔
151
        ) {
152
            // Get our body from php://input
153
            $body = file_get_contents('php://input');
3,082✔
154
        }
155

156
        // If file_get_contents() returns false or empty string, set null.
157
        if ($body === false || $body === '') {
3,453✔
158
            $body = null;
3,085✔
159
        }
160

161
        $this->uri          = $uri;
3,453✔
162
        $this->body         = $body;
3,453✔
163
        $this->userAgent    = $userAgent;
3,453✔
164
        $this->validLocales = $config->supportedLocales;
3,453✔
165

166
        parent::__construct($config);
3,453✔
167

168
        if ($uri instanceof SiteURI) {
3,453✔
169
            $this->setPath($uri->getRoutePath());
3,453✔
170
        } else {
UNCOV
171
            $this->setPath($uri->getPath());
×
172
        }
173

174
        $this->detectLocale($config);
3,453✔
175
    }
176

177
    public function __clone()
178
    {
179
        $this->input = null;
126✔
180
    }
181

182
    private function getPostMaxSize(): int
183
    {
184
        $postMaxSize = ini_get('post_max_size');
3,082✔
185

186
        return match (strtoupper(substr($postMaxSize, -1))) {
3,082✔
UNCOV
187
            'G'     => (int) str_replace('G', '', $postMaxSize) * 1024 ** 3,
×
188
            'M'     => (int) str_replace('M', '', $postMaxSize) * 1024 ** 2,
3,082✔
UNCOV
189
            'K'     => (int) str_replace('K', '', $postMaxSize) * 1024,
×
190
            default => (int) $postMaxSize,
3,082✔
191
        };
3,082✔
192
    }
193

194
    /**
195
     * Handles setting up the locale, perhaps auto-detecting through
196
     * content negotiation.
197
     *
198
     * @param App $config
199
     *
200
     * @return void
201
     */
202
    public function detectLocale($config)
203
    {
204
        $this->locale = $this->defaultLocale = $config->defaultLocale;
3,453✔
205

206
        if (! $config->negotiateLocale) {
3,453✔
207
            return;
3,453✔
208
        }
209

210
        $this->setLocale($this->negotiate('language', $config->supportedLocales));
2✔
211
    }
212

213
    /**
214
     * Provides a convenient way to work with the Negotiate class
215
     * for content negotiation.
216
     */
217
    public function negotiate(string $type, array $supported, bool $strictMatch = false): string
218
    {
219
        if ($this->negotiator === null) {
17✔
220
            $this->negotiator = Services::negotiator($this, true);
17✔
221
        }
222

223
        return match (strtolower($type)) {
17✔
224
            'media'    => $this->negotiator->media($supported, $strictMatch),
11✔
225
            'charset'  => $this->negotiator->charset($supported),
1✔
226
            'encoding' => $this->negotiator->encoding($supported),
1✔
227
            'language' => $this->negotiator->language($supported),
3✔
228
            default    => throw HTTPException::forInvalidNegotiationType($type),
17✔
229
        };
17✔
230
    }
231

232
    /**
233
     * Checks this request type.
234
     */
235
    public function is(string $type): bool
236
    {
237
        $valueUpper = strtoupper($type);
59✔
238

239
        $httpMethods = Method::all();
59✔
240

241
        if (in_array($valueUpper, $httpMethods, true)) {
59✔
242
            return $this->getMethod() === $valueUpper;
44✔
243
        }
244

245
        if ($valueUpper === 'JSON') {
15✔
246
            return str_contains($this->getHeaderLine('Content-Type'), 'application/json');
13✔
247
        }
248

249
        if ($valueUpper === 'AJAX') {
2✔
250
            return $this->isAJAX();
1✔
251
        }
252

253
        throw new InvalidArgumentException('Unknown type: ' . $type);
1✔
254
    }
255

256
    /**
257
     * Determines if this request was made from the command line (CLI).
258
     */
259
    public function isCLI(): bool
260
    {
261
        return false;
6✔
262
    }
263

264
    /**
265
     * Test to see if a request contains the HTTP_X_REQUESTED_WITH header.
266
     */
267
    public function isAJAX(): bool
268
    {
269
        return $this->hasHeader('X-Requested-With')
94✔
270
            && strtolower($this->header('X-Requested-With')->getValue()) === 'xmlhttprequest';
94✔
271
    }
272

273
    /**
274
     * Attempts to detect if the current connection is secure through
275
     * a few different methods.
276
     */
277
    public function isSecure(): bool
278
    {
279
        $https = service('superglobals')->server('HTTPS');
11✔
280

281
        if ($https !== null && strtolower($https) !== 'off') {
11✔
282
            return true;
1✔
283
        }
284

285
        if ($this->hasHeader('X-Forwarded-Proto') && $this->header('X-Forwarded-Proto')->getValue() === 'https') {
10✔
286
            return true;
1✔
287
        }
288

289
        return $this->hasHeader('Front-End-Https') && ! empty($this->header('Front-End-Https')->getValue()) && strtolower($this->header('Front-End-Https')->getValue()) !== 'off';
9✔
290
    }
291

292
    /**
293
     * Sets the URI path relative to baseURL.
294
     *
295
     * Note: Since current_url() accesses the shared request
296
     * instance, this can be used to change the "current URL"
297
     * for testing.
298
     *
299
     * @param string $path URI path relative to baseURL
300
     *
301
     * @return $this
302
     */
303
    private function setPath(string $path)
304
    {
305
        $this->path = $path;
3,453✔
306

307
        return $this;
3,453✔
308
    }
309

310
    /**
311
     * Returns the URI path relative to baseURL,
312
     * running detection as necessary.
313
     */
314
    public function getPath(): string
315
    {
316
        return $this->path;
116✔
317
    }
318

319
    /**
320
     * Sets the locale string for this request.
321
     *
322
     * @return IncomingRequest
323
     */
324
    public function setLocale(string $locale)
325
    {
326
        // If it's not a valid locale, set it
327
        // to the default locale for the site.
328
        if (! in_array($locale, $this->validLocales, true)) {
5✔
329
            $locale = $this->defaultLocale;
1✔
330
        }
331

332
        $this->locale = $locale;
5✔
333
        Locale::setDefault($locale);
5✔
334

335
        return $this;
5✔
336
    }
337

338
    /**
339
     * Set the valid locales.
340
     *
341
     * @return $this
342
     */
343
    public function setValidLocales(array $locales)
344
    {
345
        $this->validLocales = $locales;
1✔
346

347
        return $this;
1✔
348
    }
349

350
    /**
351
     * Gets the current locale, with a fallback to the default
352
     * locale if none is set.
353
     */
354
    public function getLocale(): string
355
    {
356
        return $this->locale;
578✔
357
    }
358

359
    /**
360
     * Returns the default locale as set in app/Config/App.php
361
     */
362
    public function getDefaultLocale(): string
363
    {
364
        return $this->defaultLocale;
3✔
365
    }
366

367
    /**
368
     * Fetch an item from JSON input stream with fallback to $_REQUEST object. This is the simplest way
369
     * to grab data from the request object and can be used in lieu of the
370
     * other get* methods in most cases.
371
     *
372
     * @param array|string|null $index
373
     * @param int|null          $filter Filter constant
374
     * @param array|int|null    $flags
375
     *
376
     * @return array|bool|float|int|stdClass|string|null
377
     */
378
    public function getVar($index = null, $filter = null, $flags = null)
379
    {
380
        if (
381
            str_contains($this->getHeaderLine('Content-Type'), 'application/json')
18✔
382
            && $this->body !== null
18✔
383
        ) {
384
            return $this->getJsonVar($index, false, $filter, $flags);
1✔
385
        }
386

387
        return $this->fetchGlobal('request', $index, $filter, $flags);
17✔
388
    }
389

390
    /**
391
     * A convenience method that grabs the raw input stream and decodes
392
     * the JSON into an array.
393
     *
394
     * If $assoc == true, then all objects in the response will be converted
395
     * to associative arrays.
396
     *
397
     * @param bool $assoc   Whether to return objects as associative arrays
398
     * @param int  $depth   How many levels deep to decode
399
     * @param int  $options Bitmask of options
400
     *
401
     * @see http://php.net/manual/en/function.json-decode.php
402
     *
403
     * @return array|bool|float|int|stdClass|null
404
     *
405
     * @throws HTTPException When the body is invalid as JSON.
406
     */
407
    public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0)
408
    {
409
        if ($this->body === null) {
29✔
410
            return null;
4✔
411
        }
412

413
        $result = json_decode($this->body, $assoc, $depth, $options);
25✔
414

415
        if (json_last_error() !== JSON_ERROR_NONE) {
24✔
416
            throw HTTPException::forInvalidJSON(json_last_error_msg());
4✔
417
        }
418

419
        return $result;
20✔
420
    }
421

422
    /**
423
     * Get a specific variable from a JSON input stream
424
     *
425
     * @param array|string|null $index  The variable that you want which can use dot syntax for getting specific values.
426
     * @param bool              $assoc  If true, return the result as an associative array.
427
     * @param int|null          $filter Filter Constant
428
     * @param array|int|null    $flags  Option
429
     *
430
     * @return array|bool|float|int|stdClass|string|null
431
     */
432
    public function getJsonVar($index = null, bool $assoc = false, ?int $filter = null, $flags = null)
433
    {
434
        helper('array');
6✔
435

436
        $data = $this->getJSON(true);
6✔
437
        if (! is_array($data)) {
6✔
438
            return null;
1✔
439
        }
440

441
        if (is_string($index)) {
5✔
442
            $data = dot_array_search($index, $data);
5✔
443
        } elseif (is_array($index)) {
2✔
444
            $result = [];
2✔
445

446
            foreach ($index as $key) {
2✔
447
                $result[$key] = dot_array_search($key, $data);
2✔
448
            }
449

450
            [$data, $result] = [$result, null];
2✔
451
        }
452

453
        if ($data === null) {
5✔
454
            return null;
2✔
455
        }
456

457
        $filter ??= FILTER_UNSAFE_RAW;
5✔
458
        $flags = is_array($flags) ? $flags : (is_numeric($flags) ? (int) $flags : 0);
5✔
459

460
        if ($filter !== FILTER_UNSAFE_RAW
5✔
461
            || (
462
                (is_numeric($flags) && $flags !== 0)
5✔
463
                || is_array($flags) && $flags !== []
5✔
464
            )
465
        ) {
466
            if (is_array($data)) {
2✔
467
                // Iterate over array and append filter and flags
468
                array_walk_recursive($data, static function (&$val) use ($filter, $flags): void {
1✔
469
                    $valType = gettype($val);
1✔
470
                    $val     = filter_var($val, $filter, $flags);
1✔
471

472
                    if (in_array($valType, ['int', 'integer', 'float', 'double', 'bool', 'boolean'], true) && $val !== false) {
1✔
473
                        settype($val, $valType);
1✔
474
                    }
475
                });
1✔
476
            } else {
477
                $dataType = gettype($data);
1✔
478
                $data     = filter_var($data, $filter, $flags);
1✔
479

480
                if (in_array($dataType, ['int', 'integer', 'float', 'double', 'bool', 'boolean'], true) && $data !== false) {
1✔
UNCOV
481
                    settype($data, $dataType);
×
482
                }
483
            }
484
        }
485

486
        if (! $assoc) {
5✔
487
            if (is_array($index)) {
4✔
488
                foreach ($data as &$val) {
2✔
489
                    $val = is_array($val) ? json_decode(json_encode($val)) : $val;
2✔
490
                }
491

492
                return $data;
2✔
493
            }
494

495
            return json_decode(json_encode($data));
3✔
496
        }
497

498
        return $data;
2✔
499
    }
500

501
    /**
502
     * A convenience method that grabs the raw input stream(send method in PUT, PATCH, DELETE) and decodes
503
     * the String into an array.
504
     *
505
     * @return array
506
     */
507
    public function getRawInput()
508
    {
509
        parse_str($this->body ?? '', $output);
14✔
510

511
        return $output;
14✔
512
    }
513

514
    /**
515
     * Gets a specific variable from raw input stream (send method in PUT, PATCH, DELETE).
516
     *
517
     * @param array|string|null $index  The variable that you want which can use dot syntax for getting specific values.
518
     * @param int|null          $filter Filter Constant
519
     * @param array|int|null    $flags  Option
520
     *
521
     * @return array|bool|float|int|object|string|null
522
     */
523
    public function getRawInputVar($index = null, ?int $filter = null, $flags = null)
524
    {
525
        helper('array');
10✔
526

527
        parse_str($this->body ?? '', $output);
10✔
528

529
        if (is_string($index)) {
10✔
530
            $output = dot_array_search($index, $output);
6✔
531
        } elseif (is_array($index)) {
4✔
532
            $data = [];
2✔
533

534
            foreach ($index as $key) {
2✔
535
                $data[$key] = dot_array_search($key, $output);
2✔
536
            }
537

538
            [$output, $data] = [$data, null];
2✔
539
        }
540

541
        $filter ??= FILTER_UNSAFE_RAW;
10✔
542
        $flags = is_array($flags) ? $flags : (is_numeric($flags) ? (int) $flags : 0);
10✔
543

544
        if (is_array($output)
10✔
545
            && (
546
                $filter !== FILTER_UNSAFE_RAW
10✔
547
                || (
10✔
548
                    (is_numeric($flags) && $flags !== 0)
10✔
549
                    || is_array($flags) && $flags !== []
10✔
550
                )
10✔
551
            )
552
        ) {
553
            // Iterate over array and append filter and flags
UNCOV
554
            array_walk_recursive($output, static function (&$val) use ($filter, $flags): void {
×
UNCOV
555
                $val = filter_var($val, $filter, $flags);
×
UNCOV
556
            });
×
557

UNCOV
558
            return $output;
×
559
        }
560

561
        if (is_string($output)) {
10✔
562
            return filter_var($output, $filter, $flags);
5✔
563
        }
564

565
        return $output;
5✔
566
    }
567

568
    /**
569
     * Fetch an item from GET data.
570
     *
571
     * @param array|string|null $index  Index for item to fetch from $_GET.
572
     * @param int|null          $filter A filter name to apply.
573
     * @param array|int|null    $flags
574
     *
575
     * @return array|bool|float|int|object|string|null
576
     */
577
    public function getGet($index = null, $filter = null, $flags = null)
578
    {
579
        return $this->fetchGlobal('get', $index, $filter, $flags);
70✔
580
    }
581

582
    /**
583
     * Returns a typed input data selector.
584
     */
585
    public function input(): RequestInput
586
    {
587
        return $this->input ??= new RequestInput($this, service('inputdatafactory'));
10✔
588
    }
589

590
    /**
591
     * Fetch an item from POST.
592
     *
593
     * @param array|string|null $index  Index for item to fetch from $_POST.
594
     * @param int|null          $filter A filter name to apply
595
     * @param array|int|null    $flags
596
     *
597
     * @return array|bool|float|int|object|string|null
598
     */
599
    public function getPost($index = null, $filter = null, $flags = null)
600
    {
601
        return $this->fetchGlobal('post', $index, $filter, $flags);
137✔
602
    }
603

604
    /**
605
     * Fetch an item from POST data with fallback to GET.
606
     *
607
     * @param array|string|null $index  Index for item to fetch from $_POST or $_GET
608
     * @param int|null          $filter A filter name to apply
609
     * @param array|int|null    $flags
610
     *
611
     * @return array|bool|float|int|object|string|null
612
     */
613
    public function getPostGet($index = null, $filter = null, $flags = null)
614
    {
615
        if ($index === null) {
5✔
616
            return array_merge($this->getGet($index, $filter, $flags), $this->getPost($index, $filter, $flags));
3✔
617
        }
618

619
        // Use $_POST directly here, since filter_has_var only
620
        // checks the initial POST data, not anything that might
621
        // have been added since.
622
        return service('superglobals')->post($index) !== null
2✔
623
            ? $this->getPost($index, $filter, $flags)
1✔
624
            : (service('superglobals')->get($index) !== null ? $this->getGet($index, $filter, $flags) : $this->getPost($index, $filter, $flags));
2✔
625
    }
626

627
    /**
628
     * Fetch an item from GET data with fallback to POST.
629
     *
630
     * @param array|string|null $index  Index for item to be fetched from $_GET or $_POST
631
     * @param int|null          $filter A filter name to apply
632
     * @param array|int|null    $flags
633
     *
634
     * @return array|bool|float|int|object|string|null
635
     */
636
    public function getGetPost($index = null, $filter = null, $flags = null)
637
    {
638
        if ($index === null) {
5✔
639
            return array_merge($this->getPost($index, $filter, $flags), $this->getGet($index, $filter, $flags));
3✔
640
        }
641

642
        // Use $_GET directly here, since filter_has_var only
643
        // checks the initial GET data, not anything that might
644
        // have been added since.
645
        return service('superglobals')->get($index) !== null
2✔
646
            ? $this->getGet($index, $filter, $flags)
1✔
647
            : (service('superglobals')->post($index) !== null ? $this->getPost($index, $filter, $flags) : $this->getGet($index, $filter, $flags));
2✔
648
    }
649

650
    /**
651
     * Fetch an item from the COOKIE array.
652
     *
653
     * @param array|string|null $index  Index for item to be fetched from $_COOKIE
654
     * @param int|null          $filter A filter name to be applied
655
     * @param array|int|null    $flags
656
     *
657
     * @return array|bool|float|int|object|string|null
658
     */
659
    public function getCookie($index = null, $filter = null, $flags = null)
660
    {
661
        return $this->fetchGlobal('cookie', $index, $filter, $flags);
154✔
662
    }
663

664
    /**
665
     * Fetch the user agent string
666
     *
667
     * @return UserAgent
668
     */
669
    public function getUserAgent()
670
    {
671
        return $this->userAgent;
6✔
672
    }
673

674
    /**
675
     * Attempts to get old Input data that has been flashed to the session
676
     * with redirect_with_input(). It first checks for the data in the old
677
     * POST data, then the old GET data and finally check for dot arrays
678
     *
679
     * @return array|string|null
680
     */
681
    public function getOldInput(string $key)
682
    {
683
        // If the session hasn't been started, we're done.
684
        if (! isset($_SESSION)) {
20✔
UNCOV
685
            return null;
×
686
        }
687

688
        // Get previously saved in session
689
        $old = session('_ci_old_input');
20✔
690

691
        // If no data was previously saved, we're done.
692
        if ($old === null) {
20✔
693
            return null;
6✔
694
        }
695

696
        // Check for the value in the POST array first.
697
        if (isset($old['post'][$key])) {
16✔
698
            return $old['post'][$key];
13✔
699
        }
700

701
        // Next check in the GET array.
702
        if (isset($old['get'][$key])) {
8✔
703
            return $old['get'][$key];
3✔
704
        }
705

706
        helper('array');
6✔
707

708
        // Check for an array value in POST.
709
        if (isset($old['post'])) {
6✔
710
            $value = dot_array_search($key, $old['post']);
6✔
711
            if ($value !== null) {
6✔
712
                return $value;
1✔
713
            }
714
        }
715

716
        // Check for an array value in GET.
717
        if (isset($old['get'])) {
6✔
718
            $value = dot_array_search($key, $old['get']);
3✔
719
            if ($value !== null) {
3✔
720
                return $value;
1✔
721
            }
722
        }
723

724
        // requested session key not found
725
        return null;
5✔
726
    }
727

728
    /**
729
     * Returns an array of all files that have been uploaded with this
730
     * request. Each file is represented by an UploadedFile instance.
731
     */
732
    public function getFiles(): array
733
    {
734
        if ($this->files === null) {
1✔
735
            $this->files = new FileCollection();
1✔
736
        }
737

738
        return $this->files->all(); // return all files
1✔
739
    }
740

741
    /**
742
     * Verify if a file exist, by the name of the input field used to upload it, in the collection
743
     * of uploaded files and if is have been uploaded with multiple option.
744
     *
745
     * @return array|null
746
     */
747
    public function getFileMultiple(string $fileID)
748
    {
749
        if ($this->files === null) {
61✔
750
            $this->files = new FileCollection();
61✔
751
        }
752

753
        return $this->files->getFileMultiple($fileID);
61✔
754
    }
755

756
    /**
757
     * Retrieves a single file by the name of the input field used
758
     * to upload it.
759
     *
760
     * @return UploadedFile|null
761
     */
762
    public function getFile(string $fileID)
763
    {
764
        if ($this->files === null) {
57✔
765
            $this->files = new FileCollection();
1✔
766
        }
767

768
        return $this->files->getFile($fileID);
57✔
769
    }
770
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc