Issues (536)

src/Helpers/common.php (23 issues)

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

457
        return '<input type="hidden"' . ($id !== null && $id !== '' ? ' id="' . esc($id, 'attr') . '"' : '') . ' name="' . /** @scrutinizer ignore-type */ $name . '" value="' . csrf_token() . '">';
Loading history...
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

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

469
        return '<meta' . ($id !== null && $id !== '' ? ' id="' . /** @scrutinizer ignore-type */ esc($id, 'attr') . '"' : '') . ' name="' . $name . '" content="' . csrf_token() . '">';
Loading history...
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

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

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

856
        if (is_cli() || $request->is(/** @scrutinizer ignore-type */ 'ssl')) {
Loading history...
857
            return;
858
        }
859
860
        // Si la session est active, nous devons régénérer
861
        // l'ID de session pour des raisons de sécurité.
862
        if (! on_test() && session_status() === PHP_SESSION_ACTIVE) {
863
            session()->regenerate(); // @codeCoverageIgnore
864
        }
865
866
        $uri = (string) $request->getUri()->withScheme('https');
867
868
        // Définir un en-tête HSTS
869
        $response = $response->to($uri)
870
            ->withStatus(StatusCode::TEMPORARY_REDIRECT)
871
            ->withHeader('Strict-Transport-Security', 'max-age=' . $duration)
872
            ->withStringBody('');
0 ignored issues
show
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

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