ci4
1<?php
2
3declare(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
14namespace CodeIgniter\HTTP;15
16use Config\App;17use Locale;18use RuntimeException;19
20/**
21* Represents a request from the command-line. Provides additional
22* tools to interact with that request since CLI requests are not
23* static like HTTP requests might be.
24*
25* Portions of this code were initially from the FuelPHP Framework,
26* version 1.7.x, and used here under the MIT license they were
27* originally made available under.
28*
29* http://fuelphp.com
30*
31* @see \CodeIgniter\HTTP\CLIRequestTest
32*/
33class CLIRequest extends Request34{
35/**36* Stores the segments of our cli "URI" command.
37*
38* @var array
39*/
40protected $segments = [];41
42/**43* Command line options and their values.
44*
45* @var array
46*/
47protected $options = [];48
49/**50* Command line arguments (segments and options).
51*
52* @var array
53*/
54protected $args = [];55
56/**57* Set the expected HTTP verb
58*
59* @var string
60*/
61protected $method = 'CLI';62
63/**64* Constructor
65*/
66public function __construct(App $config)67{68if (! is_cli()) {69throw new RuntimeException(static::class . ' needs to run from the command line.'); // @codeCoverageIgnore70}71
72parent::__construct($config);73
74// Don't terminate the script when the cli's tty goes away75ignore_user_abort(true);76
77$this->parseCommand();78
79// Set SiteURI for this request80$this->uri = new SiteURI($config, $this->getPath());81}82
83/**84* Returns the "path" of the request script so that it can be used
85* in routing to the appropriate controller/method.
86*
87* The path is determined by treating the command line arguments
88* as if it were a URL - up until we hit our first option.
89*
90* Example:
91* php index.php users 21 profile -foo bar
92*
93* // Routes to /users/21/profile (index is removed for routing sake)
94* // with the option foo = bar.
95*/
96public function getPath(): string97{98$path = implode('/', $this->segments);99
100return ($path === '') ? '' : $path;101}102
103/**104* Returns an associative array of all CLI options found, with
105* their values.
106*/
107public function getOptions(): array108{109return $this->options;110}111
112/**113* Returns an array of all CLI arguments (segments and options).
114*/
115public function getArgs(): array116{117return $this->args;118}119
120/**121* Returns the path segments.
122*/
123public function getSegments(): array124{125return $this->segments;126}127
128/**129* Returns the value for a single CLI option that was passed in.
130*
131* @return string|null
132*/
133public function getOption(string $key)134{135return $this->options[$key] ?? null;136}137
138/**139* Returns the options as a string, suitable for passing along on
140* the CLI to other commands.
141*
142* Example:
143* $options = [
144* 'foo' => 'bar',
145* 'baz' => 'queue some stuff'
146* ];
147*
148* getOptionString() = '-foo bar -baz "queue some stuff"'
149*/
150public function getOptionString(bool $useLongOpts = false): string151{152if ($this->options === []) {153return '';154}155
156$out = '';157
158foreach ($this->options as $name => $value) {159if ($useLongOpts && mb_strlen($name) > 1) {160$out .= "--{$name} ";161} else {162$out .= "-{$name} ";163}164
165if ($value === null) {166continue;167}168
169if (mb_strpos($value, ' ') !== false) {170$out .= '"' . $value . '" ';171} else {172$out .= "{$value} ";173}174}175
176return trim($out);177}178
179/**180* Parses the command line it was called from and collects all options
181* and valid segments.
182*
183* NOTE: I tried to use getopt but had it fail occasionally to find
184* any options, where argv has always had our back.
185*
186* @return void
187*/
188protected function parseCommand()189{190$args = $this->getServer('argv');191array_shift($args); // Scrap index.php192
193$optionValue = false;194
195foreach ($args as $i => $arg) {196if (mb_strpos($arg, '-') !== 0) {197if ($optionValue) {198$optionValue = false;199} else {200$this->segments[] = $arg;201$this->args[] = $arg;202}203
204continue;205}206
207$arg = ltrim($arg, '-');208$value = null;209
210if (isset($args[$i + 1]) && mb_strpos($args[$i + 1], '-') !== 0) {211$value = $args[$i + 1];212$optionValue = true;213}214
215$this->options[$arg] = $value;216$this->args[$arg] = $value;217}218}219
220/**221* Determines if this request was made from the command line (CLI).
222*/
223public function isCLI(): bool224{225return true;226}227
228/**229* Fetch an item from GET data.
230*
231* @param array|string|null $index Index for item to fetch from $_GET.
232* @param int|null $filter A filter name to apply.
233* @param array|int|null $flags
234*
235* @return array|null
236*/
237public function getGet($index = null, $filter = null, $flags = null)238{239return $this->returnNullOrEmptyArray($index);240}241
242/**243* Fetch an item from POST.
244*
245* @param array|string|null $index Index for item to fetch from $_POST.
246* @param int|null $filter A filter name to apply
247* @param array|int|null $flags
248*
249* @return array|null
250*/
251public function getPost($index = null, $filter = null, $flags = null)252{253return $this->returnNullOrEmptyArray($index);254}255
256/**257* Fetch an item from POST data with fallback to GET.
258*
259* @param array|string|null $index Index for item to fetch from $_POST or $_GET
260* @param int|null $filter A filter name to apply
261* @param array|int|null $flags
262*
263* @return array|null
264*/
265public function getPostGet($index = null, $filter = null, $flags = null)266{267return $this->returnNullOrEmptyArray($index);268}269
270/**271* Fetch an item from GET data with fallback to POST.
272*
273* @param array|string|null $index Index for item to be fetched from $_GET or $_POST
274* @param int|null $filter A filter name to apply
275* @param array|int|null $flags
276*
277* @return array|null
278*/
279public function getGetPost($index = null, $filter = null, $flags = null)280{281return $this->returnNullOrEmptyArray($index);282}283
284/**285* This is a place holder for calls from cookie_helper get_cookie().
286*
287* @param array|string|null $index Index for item to be fetched from $_COOKIE
288* @param int|null $filter A filter name to be applied
289* @param mixed $flags
290*
291* @return array|null
292*/
293public function getCookie($index = null, $filter = null, $flags = null)294{295return $this->returnNullOrEmptyArray($index);296}297
298/**299* @param array|string|null $index
300*
301* @return array|null
302*/
303private function returnNullOrEmptyArray($index)304{305return ($index === null || is_array($index)) ? [] : null;306}307
308/**309* Gets the current locale, with a fallback to the default
310* locale if none is set.
311*/
312public function getLocale(): string313{314return Locale::getDefault();315}316
317/**318* Checks this request type.
319*
320* @param string $type HTTP verb or 'json' or 'ajax'
321* @phpstan-param string|'get'|'post'|'put'|'delete'|'head'|'patch'|'options'|'json'|'ajax' $type
322*/
323public function is(string $type): bool324{325return false;326}327}
328