Passed
Pull Request — main (#28)
by
unknown
09:34 queued 04:20
created

is_cli()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 1
cts 1
cp 1
crap 1
rs 10
1
<?php
2
3
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
use BlitzPHP\Cli\Console\Console;
0 ignored issues
show
Bug introduced by
The type BlitzPHP\Cli\Console\Console was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
13
use BlitzPHP\Config\Config;
14
use BlitzPHP\Container\Services;
15
use BlitzPHP\Contracts\Database\ConnectionInterface;
16
use BlitzPHP\Contracts\Http\StatusCode;
17
use BlitzPHP\Contracts\Session\CookieInterface;
18
use BlitzPHP\Contracts\Session\CookieManagerInterface;
19
use BlitzPHP\Debug\Logger;
20
use BlitzPHP\Exceptions\PageNotFoundException;
21
use BlitzPHP\Exceptions\RedirectException;
22
use BlitzPHP\Http\Redirection;
23
use BlitzPHP\Http\ServerRequest;
24
use BlitzPHP\Loader\Load;
25
use BlitzPHP\Session\Store;
26
use BlitzPHP\Utilities\Helpers;
27
use BlitzPHP\Utilities\Iterable\Collection;
28
use BlitzPHP\Utilities\Support\Invader;
29
use GuzzleHttp\Psr7\Utils;
30
use Psr\Http\Message\StreamInterface;
31
32
// ================================= FONCTIONS UTIILITAIRES ESSENTIELLES ================================= //
33
34
if (! function_exists('env')) {
35
    /**
36
     * Obtient une variable d'environnement à partir des sources disponibles et fournit une émulation
37
     * pour les variables d'environnement non prises en charge ou incohérentes
38
     *
39
     * @param string     $key     Nom de la variable d'environnement
40
     * @param mixed|null $default
41
     *
42
     * @return string Paramétrage des variables d'environnement.
43
     */
44
    function env(string $key, $default = null)
45
    {
46 121
        return Helpers::env($key, $default);
47
    }
48
}
49
50
if (! function_exists('helper')) {
51
    /**
52
     * Charge un fichier d'aide en mémoire. Prend en charge les assistants d'espace de noms,
53
     * à la fois dans et hors du répertoire 'helpers' d'un répertoire à espace de noms.
54
     *
55
     * Chargera TOUS les helpers du nom correspondant, dans l'ordre suivant :
56
     *   1. app/Helpers
57
     *   2. {namespace}/Helpers
58
     *   3. system/Helpers
59
     */
60
    function helper(array|string $filenames): void
61
    {
62 56
        Load::helper($filenames);
63
    }
64
}
65
66
if (! function_exists('model')) {
67
    /**
68
     * Simple maniere d'obtenir un modele.
69
     *
70
     * @template T
71
     *
72
     * @param class-string<T>|list<class-string<T>> $name
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T>|list<class-string<T>> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>|list<class-string<T>>.
Loading history...
73
     *
74
     * @return T
75
     */
76
    function model(array|string $name, ?ConnectionInterface &$conn = null)
77
    {
78
        return Load::model($name, $conn);
79
    }
80
}
81
82
if (! function_exists('service')) {
83
    /**
84
     * Permet un accès plus propre au fichier de configuration des services.
85
     * Renvoie toujours une instance SHARED de la classe, donc l'appel de la fonction plusieurs fois renvera toujours la même instance.
86
     *
87
     * Ceux-ci sont égaux :
88
     *  - $cache = service('cache')
89
     *  - $cache = \BlitzPHP\Container\Services::cache();
90
     *
91
     * @template T
92
     *
93
     * @param class-string<T> $name
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
94
     *
95
     * @return object|T
96
     */
97
    function service(string $name, ...$params)
98
    {
99 30
        return Services::$name(...$params);
100
    }
101
}
102
103
if (! function_exists('single_service')) {
104
    /**
105
     * Autoriser l'accès propre à un service.
106
     * Renvoie toujours une nouvelle instance de la classe.
107
     *
108
     * @template T
109
     *
110
     * @param class-string<T> $name
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
111
     *
112
     * @return object|T
113
     */
114
    function single_service(string $name, ...$params)
115
    {
116
        // Assurez-vous qu'il ne s'agit PAS d'une instance partagée
117
        $params[] = false;
118
119
        return Services::$name(...$params);
120
    }
121
}
122
123
if (! function_exists('show404')) {
124
    /**
125
     * Afficher une page 404 introuvable dans le navigateur
126
     */
127
    function show404(string $message = 'The page you requested was not found.', string $heading = 'Page Not Found', array $params = []): never
128
    {
129
        throw PageNotFoundException::pageNotFound($message);
130
    }
131
}
132
133
if (! function_exists('command')) {
134
    /**
135
     * Exécute une seule commande.
136
     * Entrée attendue dans une seule chaîne comme celle qui serait utilisée sur la ligne de commande elle-même :
137
     *
138
     *  > command('migrate:create SomeMigration');
139
     *
140
     * @see https://github.com/codeigniter4/CodeIgniter4/blob/b56c85c9d09fd3b34893220b2221ed27f8d508e6/system/Common.php#L133
141
     *
142
     * @return false|string
143
     */
144
    function command(string $command)
145
    {
146 18
        $regexString = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
147 18
        $regexQuoted = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
148
149 18
        $args   = [];
150 18
        $length = strlen($command);
151 18
        $cursor = 0;
152
153
        /**
154
         * Adopté de `StringInput::tokenize()` de Symfony avec quelques modifications.
155
         *
156
         * @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Console/Input/StringInput.php
157
         */
158
        while ($cursor < $length) {
159
            if (preg_match('/\s+/A', $command, $match, 0, $cursor)) {
160
                // Rien a faire
161
            } elseif (preg_match('/' . $regexQuoted . '/A', $command, $match, 0, $cursor)) {
162 18
                $args[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2));
163
            } elseif (preg_match('/' . $regexString . '/A', $command, $match, 0, $cursor)) {
164 18
                $args[] = stripcslashes($match[1]);
165
            } else {
166
                // @codeCoverageIgnoreStart
167
                throw new InvalidArgumentException(sprintf(
168
                    'Impossible d\'analyser l\'entrée à proximité "... %s ...".',
169
                    substr($command, $cursor, 10)
170
                ));
171
                // @codeCoverageIgnoreEnd
172
            }
173
174 18
            $cursor += strlen($match[0]);
175
        }
176
177 18
        $command = array_shift($args);
178 18
        $params  = [];
179
180
        foreach ($args as $key => $arg) {
181
            if (mb_strpos($arg, '--') !== false) {
182 6
                unset($args[$key]);
183 6
                [$arg, $v]          = explode('=', $arg) + [1 => true];
184 6
                $params[trim($arg)] = is_string($v) ? trim($v) : $v;
185
            }
186
        }
187
188 18
        ob_start();
189
190 18
        service(Console::class)->call($command, $args, $params);
191
192 18
        return ob_get_clean();
193
    }
194
}
195
196
if (! function_exists('config')) {
197
    /**
198
     * GET/SET App config
199
     *
200
     * @param mixed|null $default
201
     *
202
     * @return Config|mixed|void
203
     */
204
    function config(array|string|null $key = null, $default = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
205
    {
206 191
        $config = Services::config();
207
208
        if (null === $key) {
209 24
            return $config;
210
        }
211
212
        if (is_string($key)) {
0 ignored issues
show
introduced by
The condition is_string($key) is always false.
Loading history...
213 191
            return $config->get($key, $default);
214
        }
215
216
        foreach ($key as $k => $v) {
217
            if (is_string($k)) {
218 18
                $config->set($k, $v);
219
            }
220
        }
221
222 18
        return null;
223
    }
224
}
225
226
if (! function_exists('logger')) {
227
    /**
228
     * Une méthode de commodité pour les événements de journalisation via le système Log.
229
     *
230
     * Les niveaux de journal autorisés sont :
231
     *  - emergency
232
     *  - alert
233
     *  - critical
234
     *  - error
235
     *  - warning
236
     *  - notice
237
     *  - info
238
     *  - debug
239
     *
240
     * @param int|string $level
241
     *
242
     * @return Logger|void
243
     */
244
    function logger($level = null, ?string $message = null, array $context = [])
245
    {
246
        $logger = Services::logger();
247
248
        if (empty($level) || $message === null) {
249
            return $logger;
250
        }
251
252
        $logger->log($level, $message, $context);
253
    }
254
}
255
256
if (! function_exists('cache')) {
257
    /**
258
     * Une méthode pratique qui donne accès au cache
259
     * objet. Si aucun paramètre n'est fourni, renverra l'objet,
260
     * sinon, tentera de renvoyer la valeur mise en cache.
261
     *
262
     * Exemples:
263
     *    cache()->set('foo', 'bar'); ou cache('foo', 'bar');
264
     *    $foo = cache('bar');
265
     *
266
     * @param mixed|null $value
267
     *
268
     * @return BlitzPHP\Cache\Cache|bool|mixed
269
     */
270
    function cache(?string $key = null, $value = null)
271
    {
272 6
        $cache = Services::cache();
273
274
        if ($key === null) {
275 6
            return $cache;
276
        }
277
278
        if (empty($value)) {
279 6
            return $cache->get($key);
280
        }
281
282
        return $cache->set($key, $value);
283
    }
284
}
285
286
if (! function_exists('cookie')) {
287
    /**
288
     * Une méthode pratique qui donne accès à l'objet cookie.
289
     * Si aucun paramètre n'est fourni, renverra l'objet,
290
     * sinon, tentera de renvoyer la valeur du cookie.
291
     *
292
     * Exemples:
293
     *    cookie()->make('foo', 'bar'); ou cookie('foo', 'bar');
294
     *    $foo = cookie('bar')
295
     *
296
     * @return CookieInterface|CookieManagerInterface|null
297
     */
298
    function cookie(?string $name = null, array|string|null $value = null, int $minutes = 0, array $options = [])
299
    {
300 4
        $cookie = Services::cookie();
301
302
        if (null === $name) {
303
            return $cookie;
304
        }
305
306
        if (null === $value) {
307 4
            return $cookie->get($name);
308
        }
309
310 4
        return $cookie->make($name, $value, $minutes, $options);
311
    }
312
}
313
314
if (! function_exists('session')) {
315
    /**
316
     * Une méthode pratique pour accéder à l'instance de session, ou un élément qui a été défini dans la session.
317
     *
318
     * Exemples:
319
     *    session()->set('foo', 'bar');
320
     *    $foo = session('bar');
321
     *
322
     * @return array|bool|float|int|object|Store|string|null
323
     */
324
    function session(?string $val = null)
325
    {
326
        $session = Services::session();
327
328
        // Vous retournez un seul element ?
329
        if (is_string($val)) {
330
            return $session->get($val);
331
        }
332
333
        return $session;
334
    }
335
}
336
337
// =========================== FONCTIONS DE PREVENTION D'ATTAQUE =========================== //
338
339
if (! function_exists('esc')) {
340
    /**
341
     * Effectue un simple échappement automatique des données pour des raisons de sécurité.
342
     * Pourrait envisager de rendre cela plus complexe à une date ultérieure.
343
     *
344
     * Si $data est une chaîne, il suffit alors de l'échapper et de la renvoyer.
345
     * Si $data est un tableau, alors il boucle dessus, s'échappant de chaque
346
     * 'valeur' des paires clé/valeur.
347
     *
348
     * Valeurs de contexte valides : html, js, css, url, attr, raw, null
349
     *
350
     * @param array|string $data
351
     *
352
     * @return array|string
353
     *
354
     * @throws InvalidArgumentException
355
     */
356
    function esc($data, ?string $context = 'html', ?string $encoding = null)
357
    {
358
        if (class_exists('\Laminas\Escaper\Escaper')) {
359 74
            return Helpers::esc($data, $context, $encoding);
360
        }
361
362 74
        return h($data, true, $encoding);
363
    }
364
}
365
366
if (! function_exists('h')) {
367
    /**
368
     * Méthode pratique pour htmlspecialchars.
369
     *
370
     * @param mixed       $text    Texte à envelopper dans htmlspecialchars. Fonctionne également avec des tableaux et des objets.
371
     *                             Les tableaux seront mappés et tous leurs éléments seront échappés. Les objets seront transtypés s'ils
372
     *                             implémenter une méthode `__toString`. Sinon, le nom de la classe sera utilisé.
373
     *                             Les autres types de scalaires seront renvoyés tels quels.
374
     * @param bool        $double  Encodez les entités html existantes.
375
     * @param string|null $charset Jeu de caractères à utiliser lors de l'échappement. La valeur par défaut est la valeur de configuration dans `mb_internal_encoding()` ou 'UTF-8'.
376
     *
377
     * @return mixed Texte enveloppé.
378
     */
379
    function h($text, bool $double = true, ?string $charset = null)
380
    {
381 74
        return Helpers::h($text, $double, $charset);
382
    }
383
}
384
385
if (! function_exists('purify')) {
386
    /**
387
     * Purifiez l'entrée à l'aide de la classe autonome HTMLPurifier.
388
     * Utilisez facilement plusieurs configurations de purificateur.
389
     *
390
     * @param list<string>|string $dirty_html
0 ignored issues
show
Bug introduced by
The type list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
391
     * @param false|string        $config
392
     *
393
     * @return list<string>|string
394
     */
395
    function purify($dirty_html, $config = false)
396
    {
397
        return Helpers::purify($dirty_html, $config);
0 ignored issues
show
Bug Best Practice introduced by
The expression return BlitzPHP\Utilitie...y($dirty_html, $config) returns the type string|string[] which is incompatible with the documented return type list.
Loading history...
398
    }
399
}
400
401
if (! function_exists('remove_invisible_characters')) {
402
    /**
403
     * Supprimer les caractères invisibles
404
     *
405
     * Cela empêche de prendre en sandwich des caractères nuls
406
     * entre les caractères ascii, comme Java\0script.
407
     */
408
    function remove_invisible_characters(string $str, bool $url_encoded = true): string
409
    {
410
        return Helpers::removeInvisibleCharacters($str, $url_encoded);
411
    }
412
}
413
414
if (! function_exists('stringify_attributes')) {
415
    /**
416
     * Chaîner les attributs à utiliser dans les balises HTML.
417
     *
418
     * @param array|object|string $attributes
419
     */
420
    function stringify_attributes($attributes, bool $js = false): string
421
    {
422
        return Helpers::stringifyAttributes($attributes, $js);
423
    }
424
}
425
426
// ================================= FONCTIONS DE FORMULAIRE ================================= //
427
428
if (! function_exists('csrf_token')) {
429
    /**
430
     * Renvoie la valeur de hachage actuelle pour la protection CSRF.
431
     * Peut être utilisé dans les vues lors de la construction manuelle d'input cachées, ou utilisé dans les variables javascript pour l'utilisation de l'API.
432
     */
433
    function csrf_token(): string
434
    {
435
        return Services::session()->token();
0 ignored issues
show
Bug Best Practice introduced by
The expression return BlitzPHP\Containe...ces::session()->token() could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
436
    }
437
}
438
439
if (! function_exists('csrf_field')) {
440
    /**
441
     * Génère un champ input caché à utiliser dans les formulaires générés manuellement.
442
     */
443
    function csrf_field(?string $id = null): string
444
    {
445
        $name = config('security.csrf_token_name', '_token');
446
447
        return '<input type="hidden"' . ($id !== null && $id !== '' ? ' id="' . esc($id, 'attr') . '"' : '') . ' name="' . $name . '" value="' . csrf_token() . '">';
0 ignored issues
show
Bug introduced by
Are you sure $name of type BlitzPHP\Config\Config|null can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

447
        return '<input type="hidden"' . ($id !== null && $id !== '' ? ' id="' . esc($id, 'attr') . '"' : '') . ' name="' . /** @scrutinizer ignore-type */ $name . '" value="' . csrf_token() . '">';
Loading history...
Bug introduced by
Are you sure esc($id, 'attr') of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

447
        return '<input type="hidden"' . ($id !== null && $id !== '' ? ' id="' . /** @scrutinizer ignore-type */ esc($id, 'attr') . '"' : '') . ' name="' . $name . '" value="' . csrf_token() . '">';
Loading history...
448
    }
449
}
450
451
if (! function_exists('csrf_meta')) {
452
    /**
453
     * Génère une balise méta à utiliser dans les appels javascript.
454
     */
455
    function csrf_meta(?string $id = null): string
456
    {
457
        $name = config('security.csrf_header_name', 'X-CSRF-TOKEN');
458
459
        return '<meta' . ($id !== null && $id !== '' ? ' id="' . esc($id, 'attr') . '"' : '') . ' name="' . $name . '" content="' . csrf_token() . '">';
0 ignored issues
show
Bug introduced by
Are you sure esc($id, 'attr') of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

459
        return '<meta' . ($id !== null && $id !== '' ? ' id="' . /** @scrutinizer ignore-type */ esc($id, 'attr') . '"' : '') . ' name="' . $name . '" content="' . csrf_token() . '">';
Loading history...
Bug introduced by
Are you sure $name of type BlitzPHP\Config\Config|null can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

459
        return '<meta' . ($id !== null && $id !== '' ? ' id="' . esc($id, 'attr') . '"' : '') . ' name="' . /** @scrutinizer ignore-type */ $name . '" content="' . csrf_token() . '">';
Loading history...
460
    }
461
}
462
463
if (! function_exists('method_field')) {
464
    /**
465
     * Générer un champ de formulaire pour usurper le verbe HTTP utilisé par les formulaires.
466
     */
467
    function method_field(string $method): string
468
    {
469
        if (! in_array($method = strtoupper($method), ['PUT', 'POST', 'DELETE', 'PATCH'], true)) {
470 2
            throw new InvalidArgumentException(sprintf('Methode %s invalide', $method));
471
        }
472
473 2
        return '<input type="hidden" name="_method" value="' . $method . '">';
474
    }
475
}
476
477
// ================================= FONCTIONS D'ENVIRONNEMENT D'EXECUTION ================================= //
478
479
if (! function_exists('environment')) {
480
    /**
481
     * Renvoi l'environnement d'execution actuel ou determine si on est dans un environnement specifie
482
     *
483
     * @return bool|string
484
     */
485
    function environment(array|string|null $env = null)
486
    {
487 33
        $current = env('ENVIRONMENT');
488
        if (empty($current) || $current === 'auto') {
489 33
            $current = config('app.environment');
490
        }
491
492
        if ($env === '' || $env === '0' || $env === [] || $env === null) {
0 ignored issues
show
introduced by
The condition $env === '0' is always false.
Loading history...
493
            return $current;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $current also could return the type BlitzPHP\Config\Config which is incompatible with the documented return type boolean|string.
Loading history...
494
        }
495
496
        $envMap = [
497
            'dev'     => 'development',
498
            'local'   => 'development',
499
            'prod'    => 'production',
500
            'test'    => 'testing',
501
            'stage'   => 'testing',
502
            'staging' => 'testing',
503 33
        ];
504
505 33
        $current = $envMap[$current] ?? $current;
506
507
        if (is_string($env)) {
0 ignored issues
show
introduced by
The condition is_string($env) is always false.
Loading history...
508 2
            $env = [$env];
509
        }
510
511 33
        $env = array_map(static fn ($k) => $envMap[$k] ?? $k, $env);
512
513 33
        return in_array($current, $env, true);
514
    }
515
}
516
517
if (! function_exists('on_dev')) {
518
    /**
519
     * Testez pour voir si nous sommes dans un environnement de développement.
520
     */
521
    function on_dev(bool $checkOnline = false): bool
522
    {
523
        if ($checkOnline && is_online()) {
524
            return false;
525
        }
526
527 8
        return environment(['dev', 'development', 'local']);
0 ignored issues
show
Bug Best Practice introduced by
The expression return environment(array...development', 'local')) could return the type string which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
528
    }
529
}
530
531
if (! function_exists('on_prod')) {
532
    /**
533
     * Testez pour voir si nous sommes dans un environnement de production.
534
     */
535
    function on_prod(bool $checkOnline = false): bool
536
    {
537
        if ($checkOnline && is_online()) {
538
            return true;
539
        }
540
541
        return environment(['prod', 'production']);
0 ignored issues
show
Bug Best Practice introduced by
The expression return environment(array('prod', 'production')) could return the type string which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
542
    }
543
}
544
545
if (! function_exists('on_test')) {
546
    /**
547
     * Testez pour voir si nous sommes dans un environnement de test
548
     */
549
    function on_test(): bool
550
    {
551 27
        return environment(['test', 'testing', 'stage', 'staging']);
0 ignored issues
show
Bug Best Practice introduced by
The expression return environment(array...', 'stage', 'staging')) could return the type string which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
552
    }
553
}
554
555
if (! function_exists('is_cli')) {
556
    /**
557
     * Testez pour voir si une demande a été faite à partir de la ligne de commande.
558
     */
559
    function is_cli(): bool
560
    {
561 18
        return Helpers::isCli();
562
    }
563
}
564
565
if (! function_exists('is_php')) {
566
    /**
567
     * Détermine si la version actuelle de PHP est égale ou supérieure à la valeur fournie.
568
     */
569
    function is_php(string $version): bool
570
    {
571
        return Helpers::isPhp($version);
572
    }
573
}
574
575
if (! function_exists('is_windows')) {
576
    /**
577
     * Déterminez si l'environnement actuel est basé sur Windows.
578
     */
579
    function is_windows(): bool
580
    {
581
        return PHP_OS_FAMILY === 'Windows';
582
    }
583
}
584
585
if (! function_exists('is_https')) {
586
    /**
587
     * Determines if the application is accessed via an encrypted * (HTTPS) connection.
588
     */
589
    function is_https(): bool
590
    {
591
        return Services::request()->is('ssl');
0 ignored issues
show
Bug introduced by
'ssl' of type string is incompatible with the type BlitzPHP\Http\list expected by parameter $type of BlitzPHP\Http\ServerRequest::is(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

591
        return Services::request()->is(/** @scrutinizer ignore-type */ 'ssl');
Loading history...
592
    }
593
}
594
595
if (! function_exists('is_localfile')) {
596
    /**
597
     * Vérifiez si le fichier auquel vous souhaitez accéder est un fichier local de votre application ou non
598
     */
599
    function is_localfile(string $name): bool
600
    {
601
        if (preg_match('#^' . base_url() . '#i', $name)) {
602
            return true;
603
        }
604
605 2
        return ! preg_match('#^(https?://)#i', $name);
606
    }
607
}
608
609
if (! function_exists('is_online')) {
610
    /**
611
     * Tester si l'application s'exécute en local ou en ligne.
612
     */
613
    function is_online(): bool
614
    {
615 12
        return Helpers::isOnline();
616
    }
617
}
618
619
if (! function_exists('is_connected')) {
620
    /**
621
     * Verifie si l'utilisateur a une connexion internet active.
622
     */
623
    function is_connected(): bool
624
    {
625
        return Helpers::isConnected();
626
    }
627
}
628
629
if (! function_exists('is_ajax_request')) {
630
    /**
631
     * Testez pour voir si une requête contient l'en-tête HTTP_X_REQUESTED_WITH.
632
     */
633
    function is_ajax_request(): bool
634
    {
635
        return Services::request()->is('ajax');
0 ignored issues
show
Bug introduced by
'ajax' of type string is incompatible with the type BlitzPHP\Http\list expected by parameter $type of BlitzPHP\Http\ServerRequest::is(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

635
        return Services::request()->is(/** @scrutinizer ignore-type */ 'ajax');
Loading history...
636
    }
637
}
638
639
if (! function_exists('redirection')) {
640
    /**
641
     * Redirige l'utilisateur
642
     */
643
    function redirection(string $uri = '', string $method = 'location', ?int $code = 302): never
644
    {
645
        $response = redirect()->to($uri, $code, [], null, $method);
646
647
        Services::emitter()->emitHeaders($response);
648
649
        exit(EXIT_SUCCESS);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
650
    }
651
}
652
653
if (! function_exists('redirect')) {
654
    /**
655
     * Méthode pratique qui fonctionne avec la $request globale actuelle et
656
     * l'instance $router à rediriger à l'aide de routes nommées et le routage inversé
657
     * pour déterminer l'URL à laquelle aller. Si rien n'est trouvé, traitera
658
     * comme une redirection traditionnelle et passez la chaîne, en laissant
659
     * $redirection->redirect() détermine la méthode et le code corrects.
660
     *
661
     * Si plus de contrôle est nécessaire, vous devez utiliser explicitement $response->redirect.
662
     */
663
    function redirect(?string $uri = null): Redirection
664
    {
665
        $redirection = Services::redirection();
666
667
        if ($uri !== null && $uri !== '') {
668
            return $redirection->route($uri);
669
        }
670
671
        return $redirection;
672
    }
673
}
674
675
if (! function_exists('back')) {
676
    /**
677
     * Retourne a la page precedente
678
     *
679
     * @param mixed $fallback
680
     */
681
    function back(int $code = 302, array $headers = [], $fallback = false): Redirection
682
    {
683
        return redirect()->back($code, $headers, $fallback);
684
    }
685
}
686
687
if (! function_exists('link_to')) {
688
    /**
689
     * Étant donné une chaîne de contrôleur/méthode et tous les paramètres,
690
     * tentera de créer l'URL relative à la route correspondante.
691
     *
692
     * REMARQUE : Cela nécessite que le contrôleur/la méthode
693
     * ait une route définie dans le fichier de configuration des routes.
694
     */
695
    function link_to(string $method, ...$params): string
696
    {
697
        $url = Services::routes()->reverseRoute($method, ...$params);
698
699
        if (empty($url)) {
700
            return '';
701
        }
702
703
        return site_url($url);
704
    }
705
}
706
707
if (! function_exists('clean_path')) {
708
    /**
709
     * Une méthode pratique pour nettoyer les chemins pour
710
     * une sortie plus belle. Utile pour les exceptions
711
     * gestion, journalisation des erreurs, etc.
712
     */
713
    function clean_path(string $path): string
714
    {
715 8
        $path = realpath($path) ?: $path;
716
717
        return match (true) {
718
            str_starts_with($path, APP_PATH)                                                 => 'APP_PATH' . DS . substr($path, strlen(APP_PATH)),
719
            str_starts_with($path, SYST_PATH)                                                => 'SYST_PATH' . DS . substr($path, strlen(SYST_PATH)),
720
            defined('VENDOR_PATH') && str_starts_with($path, VENDOR_PATH . 'blitz-php' . DS) => 'BLITZ_PATH' . DS . substr($path, strlen(VENDOR_PATH . 'blitz-php' . DS)),
721
            defined('VENDOR_PATH') && str_starts_with($path, VENDOR_PATH)                    => 'VENDOR_PATH' . DS . substr($path, strlen(VENDOR_PATH)),
722
            str_starts_with($path, ROOTPATH)                                                 => 'ROOTPATH' . DS . substr($path, strlen(ROOTPATH)),
723
            default                                                                          => $path,
724
        };
725
    }
726
}
727
728
if (! function_exists('old')) {
729
    /**
730
     * Fournit l'accès à "entrée ancienne" qui a été définie dans la session lors d'un redirect()-withInput().
731
     *
732
     * @param         false|string                               $escape
733
     * @param         mixed|null                                 $default
734
     * @phpstan-param false|'attr'|'css'|'html'|'js'|'raw'|'url' $escape
735
     *
736
     * @return array|string|null
737
     */
738
    function old(string $key, $default = null, $escape = 'html')
739
    {
740
        // Assurez-vous de charger la session
741
        if (session_status() === PHP_SESSION_NONE && ! on_test()) {
742
            session(); // @codeCoverageIgnore
743
        }
744
745
        // Retourne la valeur par défaut si rien n'a été trouvé dans l'ancien input.
746
        if (null === $value = Services::request()->old($key)) {
747
            return $default;
748
        }
749
750
        return $escape === false ? $value : esc($value, $escape);
751
    }
752
}
753
754
// ================================= FONCTIONS DE DEBOGAGE ================================= //
755
756
if (! function_exists('deprecationWarning')) {
757
    /**
758
     * Méthode d'assistance pour générer des avertissements d'obsolescence
759
     *
760
     * @param string $message    Le message à afficher comme avertissement d'obsolescence.
761
     * @param int    $stackFrame Le cadre de pile à inclure dans l'erreur. Par défaut à 1
762
     *                           car cela devrait pointer vers le code de l'application/du plugin.
763
     */
764
    function deprecation_warning(string $message, int $stackFrame = 1): void
765
    {
766
        Helpers::deprecationWarning($message, $stackFrame);
767
    }
768
}
769
770
if (! function_exists('pr')) {
771
    /**
772
     * print_r() convenience function.
773
     *
774
     * In terminals this will act similar to using print_r() directly, when not run on cli
775
     * print_r() will also wrap <pre> tags around the output of given variable. Similar to debug().
776
     *
777
     * This function returns the same variable that was passed.
778
     *
779
     * @param mixed $var Variable to print out.
780
     *
781
     * @return mixed the same $var that was passed to this function
782
     */
783
    function pr($var)
784
    {
785
        $template = (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg') ? '<pre class="pr">%s</pre>' : "\n%s\n\n";
786
        printf($template, trim(print_r($var, true)));
0 ignored issues
show
Bug introduced by
It seems like print_r($var, true) can also be of type true; however, parameter $string of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

786
        printf($template, trim(/** @scrutinizer ignore-type */ print_r($var, true)));
Loading history...
787
788
        return $var;
789
    }
790
}
791
792
if (! function_exists('pj')) {
793
    /**
794
     * json pretty print convenience function.
795
     *
796
     * In terminals this will act similar to using json_encode() with JSON_PRETTY_PRINT directly, when not run on cli
797
     * will also wrap <pre> tags around the output of given variable. Similar to pr().
798
     *
799
     * This function returns the same variable that was passed.
800
     *
801
     * @param mixed $var Variable to print out.
802
     *
803
     * @return mixed the same $var that was passed to this function
804
     *
805
     * @see pr()
806
     */
807
    function pj($var)
808
    {
809
        return Helpers::pj($var);
810
    }
811
}
812
813
if (! function_exists('trigger_warning')) {
814
    /**
815
     * Déclenche un E_USER_WARNING.
816
     */
817
    function trigger_warning(string $message): void
818
    {
819
        Helpers::triggerWarning($message);
820
    }
821
}
822
823
// ================================= FONCTIONS DIVERSES ================================= //
824
825
if (! function_exists('force_https')) {
826
    /**
827
     * Utilisé pour forcer l'accès à une page via HTTPS.
828
     * Utilise une redirection standard, plus définira l'en-tête HSTS
829
     * pour les navigateurs modernes qui prennent en charge, ce qui donne une meilleur
830
     * protection contre les attaques de l'homme du milieu.
831
     *
832
     * @see https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security
833
     *
834
     * @param int $duration Combien de temps l'en-tête SSL doit-il être défini ? (en secondes)
835
     *                      Par défaut à 1 an.
836
     *
837
     * @credit CodeIgniter <a href="http://codeigniter.com/">helpers force_https() - /system/Common.php</a>
838
     *
839
     * @throws RedirectException
840
     */
841
    function force_https(int $duration = 31536000, ?ServerRequest $request = null, ?Redirection $response = null): void
842
    {
843
        $request ??= Services::request();
844
        $response ??= Services::redirection();
845
846
        if (is_cli() || $request->is('ssl')) {
0 ignored issues
show
Bug introduced by
'ssl' of type string is incompatible with the type BlitzPHP\Http\list expected by parameter $type of BlitzPHP\Http\ServerRequest::is(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

846
        if (is_cli() || $request->is(/** @scrutinizer ignore-type */ 'ssl')) {
Loading history...
847
            return;
848
        }
849
850
        // Si la session est active, nous devons régénérer
851
        // l'ID de session pour des raisons de sécurité.
852
        if (! on_test() && session_status() === PHP_SESSION_ACTIVE) {
853
            Services::session()->regenerate(); // @codeCoverageIgnore
854
        }
855
856
        $uri = (string) $request->getUri()->withScheme('https');
857
858
        // Définir un en-tête HSTS
859
        $response = $response->to($uri)
860
            ->withStatus(StatusCode::TEMPORARY_REDIRECT)
861
            ->withHeader('Strict-Transport-Security', 'max-age=' . $duration)
862
            ->withStringBody('');
863
864
        throw new RedirectException($response);
865
    }
866
}
867
868
if (! function_exists('get_type_name')) {
869
    /**
870
     * Renvoie la classe d'objets ou le type var de ce n'est pas un objet
871
     *
872
     * @param mixed $var Variable à vérifier
873
     *
874
     * @return string Renvoie le nom de la classe ou le type de variable
875
     */
876
    function get_type_name($var): string
877
    {
878
        return Helpers::typeName($var);
879
    }
880
}
881
882
if (! function_exists('ip_address')) {
883
    /**
884
     * Renvoie l'adresse IP de l'utilisateur actuel
885
     */
886
    function ip_address(): string
887
    {
888
        return Services::request()->clientIp();
889
    }
890
}
891
892
if (! function_exists('is_really_writable')) {
893
    /**
894
     * Tests d'inscriptibilité des fichiers
895
     */
896
    function is_really_writable(string $file): bool
897
    {
898
        return Helpers::isReallyWritable($file);
899
    }
900
}
901
902
if (! function_exists('lang')) {
903
    /**
904
     * Une méthode pratique pour traduire une chaîne ou un tableau d'entrées et formater
905
     * le résultat avec le MessageFormatter de l'extension intl.
906
     */
907
    function lang(string $line, array $args = [], ?string $locale = null): string
908
    {
909 62
        return Services::translator($locale)->getLine($line, $args);
910
    }
911
}
912
913
if (! function_exists('__')) {
914
    /**
915
     * Une méthode pratique pour traduire une chaîne ou un tableau d'entrées et formater
916
     * le résultat avec le MessageFormatter de l'extension intl.
917
     */
918
    function __(string $line, array $args = [], ?string $locale = null): string
919
    {
920
        $tranlation = lang('App.' . $line, $args, $locale);
921
922
        return preg_replace('/^(App\.)/i', '', $tranlation);
923
    }
924
}
925
926
if (! function_exists('namespace_split')) {
927
    /**
928
     * Séparez l'espace de noms du nom de classe.
929
     *
930
     * Couramment utilisé comme `list($namespace, $className) = namespaceSplit($class);`.
931
     *
932
     * @param string $class Le nom complet de la classe, ie `BlitzPHP\Http\Request`.
933
     *
934
     * @return array Tableau avec 2 index. 0 => namespace, 1 => classname.
935
     */
936
    function namespace_split(string $class): array
937
    {
938
        $pos = strrpos($class, '\\');
939
        if ($pos === false) {
940
            return ['', $class];
941
        }
942
943
        return [substr($class, 0, $pos), substr($class, $pos + 1)];
944
    }
945
}
946
947
if (! function_exists('view_exist')) {
948
    /**
949
     * Verifie si un fichier de vue existe. Utile pour limiter les failles include
950
     */
951
    function view_exist(string $name, ?string $ext = null, array $options = []): bool
952
    {
953
        return Services::viewer()->exists($name, $ext, $options);
954
    }
955
}
956
957
if (! function_exists('view')) {
958
    /**
959
     * Saisit la classe compatible avec le RendererInterface et lui demande d'effectuer le rendu de la vue spécifiée.
960
     * Fournit simplement une méthode de commodité qui peut être utilisée dans les contrôleurs, les bibliothèques et les routes sous forme de closure.
961
     *
962
     * NOTE : Ne fournit pas d'échappement des données, ce qui doit être géré manuellement par le développeur.
963
     *
964
     * @return BlitzPHP\View\View
965
     */
966
    function view(string $view, array $data = [], array $options = [])
967
    {
968
        return Services::viewer()->make($view, $data, $options);
969
    }
970
}
971
972
if (! function_exists('component')) {
973
    /**
974
     * Les composants de vue sont utilisées dans les vues pour insérer des morceaux de HTML qui sont gérés par d'autres classes.
975
     *
976
     * @throws ReflectionException
977
     */
978
    function component(array|string $library, array|string|null $params = null, int $ttl = 0, ?string $cacheName = null): string
979
    {
980
        if (is_array($library)) {
0 ignored issues
show
introduced by
The condition is_array($library) is always true.
Loading history...
981 2
            $library = implode('::', $library);
982
        }
983
984 2
        return Services::componentLoader()->render($library, $params, $ttl, $cacheName);
985
    }
986
}
987
988
if (! function_exists('flash')) {
989
    /**
990
     * Fournisseur d'acces rapide a la classe PHP Flash
991
     *
992
     * @return FlashMessages|string
993
     */
994
    /*
995
    function flash()
996
    {
997
         @var FlashMessages $flash
998
        $flash = service(FlashMessages::class);
999
1000
        $params = func_get_args();
1001
        $type = array_shift($params);
1002
1003
        if (!empty($type)) {
1004
            if (empty($params)) {
1005
                if ($type === 'all') {
1006
                    $type = null;
1007
                }
1008
                return $flash->display($type, false);
1009
            }
1010
1011
            $message = array_shift($params);
1012
1013
            return $flash->add($message, $type, ...$params);
1014
        }
1015
1016
        return $flash;
1017
    }*/
1018
}
1019
1020
if (! function_exists('geo_ip')) {
1021
    /**
1022
     * Recuperation des coordonnees (pays, ville, etc) d'un utilisateur en fonction de son ip
1023
     */
1024
    function geo_ip(?string $ip = null): ?array
1025
    {
1026
        return json_decode(file_get_contents('http://ip-api.com/json/' . $ip), true);
1027
    }
1028
}
1029
1030
if (! function_exists('to_stream')) {
1031
    /**
1032
     * Créez un nouveau flux basé sur le type d'entrée.
1033
     *
1034
     * Options est un tableau associatif pouvant contenir les clés suivantes :
1035
     * - metadata : Tableau de métadonnées personnalisées.
1036
     * - size : Taille du flux.
1037
     *
1038
     * @param bool|callable|float|int|Iterator|resource|StreamInterface|string|null $resource Données du corps de l'entité
1039
     * @param array                                                                 $options  Additional options
1040
     *
1041
     * @uses GuzzleHttp\Psr7\stream_for
1042
     *
1043
     * @throws InvalidArgumentException si l'argument $resource n'est pas valide.
1044
     */
1045
    function to_stream($resource = '', array $options = []): StreamInterface
1046
    {
1047 2
        return Utils::streamFor($resource, $options);
1048
    }
1049
}
1050
1051
if (! function_exists('value')) {
1052
    /**
1053
     * Renvoie la valeur par défaut de la valeur donnée.
1054
     */
1055
    function value(mixed $value, ...$args): mixed
1056
    {
1057 2
        return Helpers::value($value, ...$args);
1058
    }
1059
}
1060
1061
if (! function_exists('collect')) {
1062
    /**
1063
     * Créez une collection à partir de la valeur donnée.
1064
     */
1065
    function collect(mixed $value = null): Collection
1066
    {
1067 2
        return Helpers::collect($value);
1068
    }
1069
}
1070
1071
if (! function_exists('with')) {
1072
    /**
1073
     * Renvoie la valeur donnée, éventuellement transmise via le rappel donné.
1074
     *
1075
     * @param mixed $value
1076
     */
1077
    function with($value, ?callable $callback = null): mixed
1078
    {
1079
        return Helpers::with($value, $callback);
1080
    }
1081
}
1082
1083
if (! function_exists('tap')) {
1084
    /**
1085
     * Appelez la Closure donnée avec cette instance puis renvoyez l'instance.
1086
     */
1087
    function tap(mixed $value, ?callable $callback = null): mixed
1088
    {
1089
        return Helpers::tap($value, $callback);
1090
    }
1091
}
1092
1093
if (! function_exists('last')) {
1094
    /**
1095
     * Recupere le dernier element d'un tableau
1096
     *
1097
     * @template T
1098
     *
1099
     * @param list<T> $array
1100
     *
1101
     * @return false|T
1102
     */
1103
    function last(array $array)
1104
    {
1105
        return end($array);
1106
    }
1107
}
1108
1109
if (! function_exists('invade')) {
1110
    /**
1111
     * Cette classe offre une fonction d'invasion qui vous permettra de lire / écrire des propriétés privées d'un objet.
1112
     * Il vous permettra également de définir, obtenir et appeler des méthodes privées.
1113
     *
1114
     * @return Invader
1115
     *
1116
     * @see https://github.com/spatie/invade/blob/main/src/Invader.php
1117
     */
1118
    function invade(object $object)
1119
    {
1120
        return Invader::make($object);
1121
    }
1122
}
1123