Passed
Push — main ( 040cbb...031be7 )
by Dimitri
05:05
created

single_service()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 6
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
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\Cache\Cache;
13
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...
14
use BlitzPHP\Config\Config;
15
use BlitzPHP\Container\Services;
16
use BlitzPHP\Contracts\Database\ConnectionInterface;
17
use BlitzPHP\Contracts\Http\StatusCode;
18
use BlitzPHP\Contracts\Session\CookieInterface;
19
use BlitzPHP\Contracts\Session\CookieManagerInterface;
20
use BlitzPHP\Debug\Logger;
21
use BlitzPHP\Exceptions\PageNotFoundException;
22
use BlitzPHP\Exceptions\RedirectException;
23
use BlitzPHP\Http\Redirection;
24
use BlitzPHP\Http\ServerRequest;
25
use BlitzPHP\Loader\Load;
26
use BlitzPHP\Session\Store;
27
use BlitzPHP\Utilities\Helpers;
28
use BlitzPHP\Utilities\Iterable\Collection;
29
use BlitzPHP\Utilities\Support\Invader;
30
use GuzzleHttp\Psr7\Utils;
31
use Psr\Http\Message\StreamInterface;
32
33
// ================================= FONCTIONS UTIILITAIRES ESSENTIELLES ================================= //
34
35
if (! function_exists('env')) {
36
    /**
37
     * Obtient une variable d'environnement à partir des sources disponibles et fournit une émulation
38
     * pour les variables d'environnement non prises en charge ou incohérentes
39
     *
40
     * @param string     $key     Nom de la variable d'environnement
41
     * @param mixed|null $default
42
     *
43
     * @return string Paramétrage des variables d'environnement.
44
     */
45
    function env(string $key, $default = null)
46
    {
47 123
        return Helpers::env($key, $default);
48
    }
49
}
50
51
if (! function_exists('helper')) {
52
    /**
53
     * Charge un fichier d'aide en mémoire. Prend en charge les assistants d'espace de noms,
54
     * à la fois dans et hors du répertoire 'helpers' d'un répertoire à espace de noms.
55
     *
56
     * Chargera TOUS les helpers du nom correspondant, dans l'ordre suivant :
57
     *   1. app/Helpers
58
     *   2. {namespace}/Helpers
59
     *   3. system/Helpers
60
     */
61
    function helper(array|string $filenames): void
62
    {
63 62
        Load::helper($filenames);
64
    }
65
}
66
67
if (! function_exists('model')) {
68
    /**
69
     * Simple maniere d'obtenir un modele.
70
     *
71
     * @template T
72
     *
73
     * @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...
74
     *
75
     * @return T
76
     */
77
    function model(array|string $name, ?ConnectionInterface &$conn = null)
78
    {
79
        return Load::model($name, $conn);
80
    }
81
}
82
83
if (! function_exists('service')) {
84
    /**
85
     * Permet un accès plus propre au fichier de configuration des services.
86
     * Renvoie toujours une instance SHARED de la classe, donc l'appel de la fonction plusieurs fois renvera toujours la même instance.
87
     *
88
     * Ceux-ci sont égaux :
89
     *  - $cache = service('cache')
90
     *  - $cache = \BlitzPHP\Container\Services::cache();
91
     *
92
     * @template T
93
     *
94
     * @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...
95
     *
96
     * @return object|T
97
     */
98
    function service(string $name, ...$params)
99
    {
100 252
        return Services::$name(...$params);
101
    }
102
}
103
104
if (! function_exists('single_service')) {
105
    /**
106
     * Autoriser l'accès propre à un service.
107
     * Renvoie toujours une nouvelle instance de la classe.
108
     *
109
     * @template T
110
     *
111
     * @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...
112
     *
113
     * @return object|T
114
     */
115
    function single_service(string $name, ...$params)
116
    {
117
        // Assurez-vous qu'il ne s'agit PAS d'une instance partagée
118 37
        $params[] = false;
119
120 37
        return service($name, ...$params);
121
    }
122
}
123
124
if (! function_exists('show404')) {
125
    /**
126
     * Afficher une page 404 introuvable dans le navigateur
127
     */
128
    function show404(string $message = 'The page you requested was not found.', string $heading = 'Page Not Found', array $params = []): never
129
    {
130
        throw PageNotFoundException::pageNotFound($message);
131
    }
132
}
133
134
if (! function_exists('command')) {
135
    /**
136
     * Exécute une seule commande.
137
     * Entrée attendue dans une seule chaîne comme celle qui serait utilisée sur la ligne de commande elle-même :
138
     *
139
     *  > command('migrate:create SomeMigration');
140
     *
141
     * @see https://github.com/codeigniter4/CodeIgniter4/blob/b56c85c9d09fd3b34893220b2221ed27f8d508e6/system/Common.php#L133
142
     *
143
     * @return false|string
144
     */
145
    function command(string $command)
146
    {
147 20
        $regexString = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
148 20
        $regexQuoted = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
149
150 20
        $args   = [];
151 20
        $length = strlen($command);
152 20
        $cursor = 0;
153
154
        /**
155
         * Adopté de `StringInput::tokenize()` de Symfony avec quelques modifications.
156
         *
157
         * @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Console/Input/StringInput.php
158
         */
159
        while ($cursor < $length) {
160
            if (preg_match('/\s+/A', $command, $match, 0, $cursor)) {
161
                // Rien a faire
162
            } elseif (preg_match('/' . $regexQuoted . '/A', $command, $match, 0, $cursor)) {
163 20
                $args[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2));
164
            } elseif (preg_match('/' . $regexString . '/A', $command, $match, 0, $cursor)) {
165 20
                $args[] = stripcslashes($match[1]);
166
            } else {
167
                // @codeCoverageIgnoreStart
168
                throw new InvalidArgumentException(sprintf(
169
                    'Impossible d\'analyser l\'entrée à proximité "... %s ...".',
170
                    substr($command, $cursor, 10)
171
                ));
172
                // @codeCoverageIgnoreEnd
173
            }
174
175 20
            $cursor += strlen($match[0]);
176
        }
177
178 20
        $command = array_shift($args);
179 20
        $params  = [];
180
181
        foreach ($args as $key => $arg) {
182
            if (mb_strpos($arg, '--') !== false) {
183 8
                unset($args[$key]);
184 8
                [$arg, $v]          = explode('=', $arg) + [1 => true];
185 8
                $params[trim($arg)] = is_string($v) ? trim($v) : $v;
186
            }
187
        }
188
189 20
        ob_start();
190
191 20
        service(Console::class)->call($command, $args, $params);
192
193 20
        return ob_get_clean();
194
    }
195
}
196
197
if (! function_exists('config')) {
198
    /**
199
     * GET/SET App config
200
     *
201
     * @param mixed|null $default
202
     *
203
     * @return Config|mixed|void
204
     */
205
    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...
206
    {
207
        /** @var Config */
208 211
        $config = service('config');
209
210
        if (null === $key) {
211 24
            return $config;
212
        }
213
214
        if (is_string($key)) {
0 ignored issues
show
introduced by
The condition is_string($key) is always false.
Loading history...
215 211
            return $config->get($key, $default);
216
        }
217
218
        foreach ($key as $k => $v) {
219
            if (is_string($k)) {
220 18
                $config->set($k, $v);
221
            }
222
        }
223
224 18
        return null;
225
    }
226
}
227
228
if (! function_exists('logger')) {
229
    /**
230
     * Une méthode de commodité pour les événements de journalisation via le système Log.
231
     *
232
     * Les niveaux de journal autorisés sont :
233
     *  - emergency
234
     *  - alert
235
     *  - critical
236
     *  - error
237
     *  - warning
238
     *  - notice
239
     *  - info
240
     *  - debug
241
     *
242
     * @param int|string $level
243
     *
244
     * @return Logger|void
245
     */
246
    function logger($level = null, ?string $message = null, array $context = [])
247
    {
248
        /** @var Logger */
249
        $logger = service('logger');
250
251
        if (empty($level) || $message === null) {
252
            return $logger;
253
        }
254
255
        $logger->log($level, $message, $context);
256
    }
257
}
258
259
if (! function_exists('cache')) {
260
    /**
261
     * Une méthode pratique qui donne accès au cache
262
     * objet. Si aucun paramètre n'est fourni, renverra l'objet,
263
     * sinon, tentera de renvoyer la valeur mise en cache.
264
     *
265
     * Exemples:
266
     *    cache()->set('foo', 'bar'); ou cache('foo', 'bar');
267
     *    $foo = cache('bar');
268
     *
269
     * @param mixed|null $value
270
     *
271
     * @return bool|Cache|mixed
272
     */
273
    function cache(?string $key = null, $value = null)
274
    {
275
        /** @var Cache */
276 6
        $cache = service('cache');
277
278
        if ($key === null) {
279 6
            return $cache;
280
        }
281
282
        if (empty($value)) {
283 6
            return $cache->get($key);
284
        }
285
286
        return $cache->set($key, $value);
287
    }
288
}
289
290
if (! function_exists('cookie')) {
291
    /**
292
     * Une méthode pratique qui donne accès à l'objet cookie.
293
     * Si aucun paramètre n'est fourni, renverra l'objet,
294
     * sinon, tentera de renvoyer la valeur du cookie.
295
     *
296
     * Exemples:
297
     *    cookie()->make('foo', 'bar'); ou cookie('foo', 'bar');
298
     *    $foo = cookie('bar')
299
     *
300
     * @return CookieInterface|CookieManagerInterface|null
301
     */
302
    function cookie(?string $name = null, array|string|null $value = null, int $minutes = 0, array $options = [])
303
    {
304
        /** @var CookieManagerInterface */
305 4
        $cookie = service('cookie');
306
307
        if (null === $name) {
308
            return $cookie;
309
        }
310
311
        if (null === $value) {
312 4
            return $cookie->get($name);
313
        }
314
315 4
        return $cookie->make($name, $value, $minutes, $options);
316
    }
317
}
318
319
if (! function_exists('session')) {
320
    /**
321
     * Une méthode pratique pour accéder à l'instance de session, ou un élément qui a été défini dans la session.
322
     *
323
     * Exemples:
324
     *    session()->set('foo', 'bar');
325
     *    $foo = session('bar');
326
     *
327
     * @return array|bool|float|int|object|Store|string|null
328
     */
329
    function session(?string $val = null)
330
    {
331
        /** @var Store */
332
        $session = service('session');
333
334
        // Vous retournez un seul element ?
335
        if (is_string($val)) {
336
            return $session->get($val);
337
        }
338
339
        return $session;
340
    }
341
}
342
343
// =========================== FONCTIONS DE PREVENTION D'ATTAQUE =========================== //
344
345
if (! function_exists('esc')) {
346
    /**
347
     * Effectue un simple échappement automatique des données pour des raisons de sécurité.
348
     * Pourrait envisager de rendre cela plus complexe à une date ultérieure.
349
     *
350
     * Si $data est une chaîne, il suffit alors de l'échapper et de la renvoyer.
351
     * Si $data est un tableau, alors il boucle dessus, s'échappant de chaque
352
     * 'valeur' des paires clé/valeur.
353
     *
354
     * Valeurs de contexte valides : html, js, css, url, attr, raw, null
355
     *
356
     * @param array|string $data
357
     *
358
     * @return array|string
359
     *
360
     * @throws InvalidArgumentException
361
     */
362
    function esc($data, ?string $context = 'html', ?string $encoding = null)
363
    {
364
        if (class_exists('\Laminas\Escaper\Escaper')) {
365 76
            return Helpers::esc($data, $context, $encoding);
366
        }
367
368 76
        return h($data, true, $encoding);
369
    }
370
}
371
372
if (! function_exists('h')) {
373
    /**
374
     * Méthode pratique pour htmlspecialchars.
375
     *
376
     * @param mixed       $text    Texte à envelopper dans htmlspecialchars. Fonctionne également avec des tableaux et des objets.
377
     *                             Les tableaux seront mappés et tous leurs éléments seront échappés. Les objets seront transtypés s'ils
378
     *                             implémenter une méthode `__toString`. Sinon, le nom de la classe sera utilisé.
379
     *                             Les autres types de scalaires seront renvoyés tels quels.
380
     * @param bool        $double  Encodez les entités html existantes.
381
     * @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'.
382
     *
383
     * @return mixed Texte enveloppé.
384
     */
385
    function h($text, bool $double = true, ?string $charset = null)
386
    {
387 76
        return Helpers::h($text, $double, $charset);
388
    }
389
}
390
391
if (! function_exists('purify')) {
392
    /**
393
     * Purifiez l'entrée à l'aide de la classe autonome HTMLPurifier.
394
     * Utilisez facilement plusieurs configurations de purificateur.
395
     *
396
     * @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...
397
     * @param false|string        $config
398
     *
399
     * @return list<string>|string
400
     */
401
    function purify($dirty_html, $config = false)
402
    {
403
        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...
404
    }
405
}
406
407
if (! function_exists('remove_invisible_characters')) {
408
    /**
409
     * Supprimer les caractères invisibles
410
     *
411
     * Cela empêche de prendre en sandwich des caractères nuls
412
     * entre les caractères ascii, comme Java\0script.
413
     */
414
    function remove_invisible_characters(string $str, bool $url_encoded = true): string
415
    {
416
        return Helpers::removeInvisibleCharacters($str, $url_encoded);
417
    }
418
}
419
420
if (! function_exists('stringify_attributes')) {
421
    /**
422
     * Chaîner les attributs à utiliser dans les balises HTML.
423
     *
424
     * @param array|object|string $attributes
425
     */
426
    function stringify_attributes($attributes, bool $js = false): string
427
    {
428
        return Helpers::stringifyAttributes($attributes, $js);
429
    }
430
}
431
432
// ================================= FONCTIONS DE FORMULAIRE ================================= //
433
434
if (! function_exists('csrf_token')) {
435
    /**
436
     * Renvoie la valeur de hachage actuelle pour la protection CSRF.
437
     * 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.
438
     */
439
    function csrf_token(): string
440
    {
441
        return session()->token();
442
    }
443
}
444
445
if (! function_exists('csrf_field')) {
446
    /**
447
     * Génère un champ input caché à utiliser dans les formulaires générés manuellement.
448
     */
449
    function csrf_field(?string $id = null): string
450
    {
451
        $name = config('security.csrf_token_name', '_token');
452
453
        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 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

453
        return '<input type="hidden"' . ($id !== null && $id !== '' ? ' id="' . /** @scrutinizer ignore-type */ esc($id, 'attr') . '"' : '') . ' name="' . $name . '" value="' . csrf_token() . '">';
Loading history...
Bug introduced by
Are you sure $name of type T|null|object 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

453
        return '<input type="hidden"' . ($id !== null && $id !== '' ? ' id="' . esc($id, 'attr') . '"' : '') . ' name="' . /** @scrutinizer ignore-type */ $name . '" value="' . csrf_token() . '">';
Loading history...
454
    }
455
}
456
457
if (! function_exists('csrf_meta')) {
458
    /**
459
     * Génère une balise méta à utiliser dans les appels javascript.
460
     */
461
    function csrf_meta(?string $id = null): string
462
    {
463
        $name = config('security.csrf_header_name', 'X-CSRF-TOKEN');
464
465
        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

465
        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 T|null|object 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

465
        return '<meta' . ($id !== null && $id !== '' ? ' id="' . esc($id, 'attr') . '"' : '') . ' name="' . /** @scrutinizer ignore-type */ $name . '" content="' . csrf_token() . '">';
Loading history...
466
    }
467
}
468
469
if (! function_exists('method_field')) {
470
    /**
471
     * Générer un champ de formulaire pour usurper le verbe HTTP utilisé par les formulaires.
472
     */
473
    function method_field(string $method): string
474
    {
475
        if (! in_array($method = strtoupper($method), ['PUT', 'POST', 'DELETE', 'PATCH'], true)) {
476 2
            throw new InvalidArgumentException(sprintf('Methode %s invalide', $method));
477
        }
478
479 2
        return '<input type="hidden" name="_method" value="' . $method . '">';
480
    }
481
}
482
483
// ================================= FONCTIONS D'ENVIRONNEMENT D'EXECUTION ================================= //
484
485
if (! function_exists('environment')) {
486
    /**
487
     * Renvoi l'environnement d'execution actuel ou determine si on est dans un environnement specifie
488
     *
489
     * @return bool|string
490
     */
491
    function environment(array|string|null $env = null)
492
    {
493 35
        $current = env('ENVIRONMENT');
494
        if (empty($current) || $current === 'auto') {
495 35
            $current = config('app.environment');
496
        }
497
498
        if ($env === '' || $env === '0' || $env === [] || $env === null) {
0 ignored issues
show
introduced by
The condition $env === '0' is always false.
Loading history...
499
            return $current;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $current also could return the type object which is incompatible with the documented return type boolean|string.
Loading history...
500
        }
501
502
        $envMap = [
503
            'dev'     => 'development',
504
            'local'   => 'development',
505
            'prod'    => 'production',
506
            'test'    => 'testing',
507
            'stage'   => 'testing',
508
            'staging' => 'testing',
509 35
        ];
510
511 35
        $current = $envMap[$current] ?? $current;
512
513
        if (is_string($env)) {
0 ignored issues
show
introduced by
The condition is_string($env) is always false.
Loading history...
514 2
            $env = [$env];
515
        }
516
517 35
        $env = array_map(static fn ($k) => $envMap[$k] ?? $k, $env);
518
519 35
        return in_array($current, $env, true);
520
    }
521
}
522
523
if (! function_exists('on_dev')) {
524
    /**
525
     * Testez pour voir si nous sommes dans un environnement de développement.
526
     */
527
    function on_dev(bool $checkOnline = false): bool
528
    {
529
        if ($checkOnline && is_online()) {
530
            return false;
531
        }
532
533 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...
534
    }
535
}
536
537
if (! function_exists('on_prod')) {
538
    /**
539
     * Testez pour voir si nous sommes dans un environnement de production.
540
     */
541
    function on_prod(bool $checkOnline = false): bool
542
    {
543
        if ($checkOnline && is_online()) {
544
            return true;
545
        }
546
547
        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...
548
    }
549
}
550
551
if (! function_exists('on_test')) {
552
    /**
553
     * Testez pour voir si nous sommes dans un environnement de test
554
     */
555
    function on_test(): bool
556
    {
557 29
        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...
558
    }
559
}
560
561
if (! function_exists('is_cli')) {
562
    /**
563
     * Testez pour voir si une demande a été faite à partir de la ligne de commande.
564
     */
565
    function is_cli(): bool
566
    {
567 20
        return Helpers::isCli();
568
    }
569
}
570
571
if (! function_exists('is_php')) {
572
    /**
573
     * Détermine si la version actuelle de PHP est égale ou supérieure à la valeur fournie.
574
     */
575
    function is_php(string $version): bool
576
    {
577
        return Helpers::isPhp($version);
578
    }
579
}
580
581
if (! function_exists('is_windows')) {
582
    /**
583
     * Déterminez si l'environnement actuel est basé sur Windows.
584
     */
585
    function is_windows(): bool
586
    {
587
        return PHP_OS_FAMILY === 'Windows';
588
    }
589
}
590
591
if (! function_exists('is_https')) {
592
    /**
593
     * Determines if the application is accessed via an encrypted * (HTTPS) connection.
594
     */
595
    function is_https(): bool
596
    {
597
        return service('request')->is('ssl');
598
    }
599
}
600
601
if (! function_exists('is_localfile')) {
602
    /**
603
     * Vérifiez si le fichier auquel vous souhaitez accéder est un fichier local de votre application ou non
604
     */
605
    function is_localfile(string $name): bool
606
    {
607
        if (preg_match('#^' . base_url() . '#i', $name)) {
608
            return true;
609
        }
610
611 2
        return ! preg_match('#^(https?://)#i', $name);
612
    }
613
}
614
615
if (! function_exists('is_online')) {
616
    /**
617
     * Tester si l'application s'exécute en local ou en ligne.
618
     */
619
    function is_online(): bool
620
    {
621 12
        return Helpers::isOnline();
622
    }
623
}
624
625
if (! function_exists('is_connected')) {
626
    /**
627
     * Verifie si l'utilisateur a une connexion internet active.
628
     */
629
    function is_connected(): bool
630
    {
631
        return Helpers::isConnected();
632
    }
633
}
634
635
if (! function_exists('is_ajax_request')) {
636
    /**
637
     * Testez pour voir si une requête contient l'en-tête HTTP_X_REQUESTED_WITH.
638
     */
639
    function is_ajax_request(): bool
640
    {
641
        return service('request')->is('ajax');
642
    }
643
}
644
645
if (! function_exists('redirection')) {
646
    /**
647
     * Redirige l'utilisateur
648
     */
649
    function redirection(string $uri = '', string $method = 'location', ?int $code = 302): never
650
    {
651
        $response = redirect()->to($uri, $code, [], null, $method);
652
653
        service('emitter')->emitHeaders($response);
654
655
        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...
656
    }
657
}
658
659
if (! function_exists('redirect')) {
660
    /**
661
     * Méthode pratique qui fonctionne avec la $request globale actuelle et
662
     * l'instance $router à rediriger à l'aide de routes nommées et le routage inversé
663
     * pour déterminer l'URL à laquelle aller. Si rien n'est trouvé, traitera
664
     * comme une redirection traditionnelle et passez la chaîne, en laissant
665
     * $redirection->redirect() détermine la méthode et le code corrects.
666
     *
667
     * Si plus de contrôle est nécessaire, vous devez utiliser explicitement $response->redirect.
668
     */
669
    function redirect(?string $uri = null): Redirection
670
    {
671
        $redirection = service('redirection');
672
673
        if ($uri !== null && $uri !== '') {
674
            return $redirection->route($uri);
675
        }
676
677
        return $redirection;
678
    }
679
}
680
681
if (! function_exists('back')) {
682
    /**
683
     * Retourne a la page precedente
684
     *
685
     * @param mixed $fallback
686
     */
687
    function back(int $code = 302, array $headers = [], $fallback = false): Redirection
688
    {
689
        return redirect()->back($code, $headers, $fallback);
690
    }
691
}
692
693
if (! function_exists('link_to')) {
694
    /**
695
     * Étant donné une chaîne de contrôleur/méthode et tous les paramètres,
696
     * tentera de créer l'URL relative à la route correspondante.
697
     *
698
     * REMARQUE : Cela nécessite que le contrôleur/la méthode
699
     * ait une route définie dans le fichier de configuration des routes.
700
     */
701
    function link_to(string $method, ...$params): string
702
    {
703
        $url = service('routes')->reverseRoute($method, ...$params);
704
705
        if (empty($url)) {
706
            return '';
707
        }
708
709
        return site_url($url);
710
    }
711
}
712
713
if (! function_exists('clean_path')) {
714
    /**
715
     * Une méthode pratique pour nettoyer les chemins pour
716
     * une sortie plus belle. Utile pour les exceptions
717
     * gestion, journalisation des erreurs, etc.
718
     */
719
    function clean_path(string $path): string
720
    {
721 8
        $path = realpath($path) ?: $path;
722
723
        return match (true) {
724
            str_starts_with($path, APP_PATH)                                                 => 'APP_PATH' . DS . substr($path, strlen(APP_PATH)),
725
            str_starts_with($path, SYST_PATH)                                                => 'SYST_PATH' . DS . substr($path, strlen(SYST_PATH)),
726
            defined('VENDOR_PATH') && str_starts_with($path, VENDOR_PATH . 'blitz-php' . DS) => 'BLITZ_PATH' . DS . substr($path, strlen(VENDOR_PATH . 'blitz-php' . DS)),
727
            defined('VENDOR_PATH') && str_starts_with($path, VENDOR_PATH)                    => 'VENDOR_PATH' . DS . substr($path, strlen(VENDOR_PATH)),
728
            str_starts_with($path, ROOTPATH)                                                 => 'ROOTPATH' . DS . substr($path, strlen(ROOTPATH)),
729
            default                                                                          => $path,
730
        };
731
    }
732
}
733
734
if (! function_exists('old')) {
735
    /**
736
     * Fournit l'accès à "entrée ancienne" qui a été définie dans la session lors d'un redirect()-withInput().
737
     *
738
     * @param         false|string                               $escape
739
     * @param         mixed|null                                 $default
740
     * @phpstan-param false|'attr'|'css'|'html'|'js'|'raw'|'url' $escape
741
     *
742
     * @return array|string|null
743
     */
744
    function old(string $key, $default = null, $escape = 'html')
745
    {
746
        // Assurez-vous de charger la session
747
        if (session_status() === PHP_SESSION_NONE && ! on_test()) {
748
            session(); // @codeCoverageIgnore
749
        }
750
751
        // Retourne la valeur par défaut si rien n'a été trouvé dans l'ancien input.
752
        if (null === $value = service('request')->old($key)) {
753
            return $default;
754
        }
755
756
        return $escape === false ? $value : esc($value, $escape);
757
    }
758
}
759
760
// ================================= FONCTIONS DE DEBOGAGE ================================= //
761
762
if (! function_exists('deprecationWarning')) {
763
    /**
764
     * Méthode d'assistance pour générer des avertissements d'obsolescence
765
     *
766
     * @param string $message    Le message à afficher comme avertissement d'obsolescence.
767
     * @param int    $stackFrame Le cadre de pile à inclure dans l'erreur. Par défaut à 1
768
     *                           car cela devrait pointer vers le code de l'application/du plugin.
769
     */
770
    function deprecation_warning(string $message, int $stackFrame = 1): void
771
    {
772
        Helpers::deprecationWarning($message, $stackFrame);
773
    }
774
}
775
776
if (! function_exists('pr')) {
777
    /**
778
     * print_r() convenience function.
779
     *
780
     * In terminals this will act similar to using print_r() directly, when not run on cli
781
     * print_r() will also wrap <pre> tags around the output of given variable. Similar to debug().
782
     *
783
     * This function returns the same variable that was passed.
784
     *
785
     * @param mixed $var Variable to print out.
786
     *
787
     * @return mixed the same $var that was passed to this function
788
     */
789
    function pr($var)
790
    {
791
        $template = (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg') ? '<pre class="pr">%s</pre>' : "\n%s\n\n";
792
        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

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

852
        if (is_cli() || $request->is(/** @scrutinizer ignore-type */ 'ssl')) {
Loading history...
853
            return;
854
        }
855
856
        // Si la session est active, nous devons régénérer
857
        // l'ID de session pour des raisons de sécurité.
858
        if (! on_test() && session_status() === PHP_SESSION_ACTIVE) {
859
            session()->regenerate(); // @codeCoverageIgnore
860
        }
861
862
        $uri = (string) $request->getUri()->withScheme('https');
863
864
        // Définir un en-tête HSTS
865
        $response = $response->to($uri)
866
            ->withStatus(StatusCode::TEMPORARY_REDIRECT)
867
            ->withHeader('Strict-Transport-Security', 'max-age=' . $duration)
868
            ->withStringBody('');
0 ignored issues
show
Bug introduced by
The method withStringBody() does not exist on Psr\Http\Message\MessageInterface. It seems like you code against a sub-type of Psr\Http\Message\MessageInterface such as BlitzPHP\Http\ServerRequest or BlitzPHP\Http\Response. ( Ignorable by Annotation )

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

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