Passed
Push — main ( c69a6f...6bc794 )
by Dimitri
11:25
created

route()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 7
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\Container\Services;
13
use BlitzPHP\Core\App;
14
use BlitzPHP\Exceptions\RouterException;
15
use BlitzPHP\Http\ServerRequest;
16
use BlitzPHP\Http\Uri;
17
use BlitzPHP\Utilities\Helpers;
18
19
/**
20
 * FONCTIONS DE MANIPULATION D'URL
21
 *
22
 * @credit	<a href="https://codeigniter.com">CodeIgniter 4.2 - url_helper</a>
23
 */
24
25
// =================================  ================================= //
26
27
if (! function_exists('site_url')) {
28
    /**
29
     * Renvoie une URL de site telle que définie par la configuration de l'application.
30
     *
31
     * @param mixed $relativePath Chaîne d'URI ou tableau de segments d'URI
32
     */
33
    function site_url($relativePath = '', ?string $scheme = null): string
34
    {
35
        if (is_array($relativePath)) {
36
            $relativePath = implode('/', $relativePath);
37
        }
38
39
        $uri = App::getUri($relativePath);
40
41
        return Uri::createURIString(
42
            $scheme ?? $uri->getScheme(),
43
            $uri->getAuthority(),
44
            $uri->getPath(),
45
            $uri->getQuery(),
46
            $uri->getFragment()
47
        );
48
    }
49
}
50
51
if (! function_exists('base_url')) {
52
    /**
53
     * Renvoie l'URL de base telle que définie par la configuration de l'application.
54
     * Les URL de base sont des URL de site coupées sans la page d'index.
55
     *
56
     * @param mixed $relativePath Chaîne d'URI ou tableau de segments d'URI
57
     */
58
    function base_url($relativePath = '', ?string $scheme = null): string
59
    {
60
        $index_page = index_page();
61
        config('app.index_page', '', true);
0 ignored issues
show
Unused Code introduced by
The call to config() has too many arguments starting with true. ( Ignorable by Annotation )

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

61
        /** @scrutinizer ignore-call */ 
62
        config('app.index_page', '', true);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
62
63
        $url = rtrim(site_url($relativePath, $scheme), '/');
64
        config('app.index_page', $index_page, true);
65
66
        return $url;
67
    }
68
}
69
70
if (! function_exists('current_url')) {
71
    /**
72
     * Renvoie l'URL complète (y compris les segments) de la page où cette fonction est placée
73
     *
74
     * @param bool $returnObject True pour renvoyer un objet au lieu d'une chaîne
75
     *
76
     * @return \BlitzPHP\Http\Uri|string
77
     */
78
    function current_url(bool $returnObject = false, ?ServerRequest $request = null)
79
    {
80
        $request ??= Services::request();
81
        $path = $request->getPath();
82
83
        // Ajouter des chaine de requêtes et des fragments
84
        if ($query = $request->getUri()->getQuery()) {
85
            $path .= '?' . $query;
86
        }
87
        if ($fragment = $request->getUri()->getFragment()) {
88
            $path .= '#' . $fragment;
89
        }
90
91
        $uri = App::getUri($path);
92
93
        return $returnObject ? $uri : Uri::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath());
94
    }
95
}
96
97
if (! function_exists('previous_url')) {
98
    /**
99
     * Renvoie l'URL précédente sur laquelle se trouvait le visiteur actuel. Pour des raisons de sécurité
100
     * nous vérifions d'abord une variable de session enregistrée, si elle existe, et l'utilisons.
101
     * Si ce n'est pas disponible, cependant, nous utiliserons une URL épurée de $_SERVER['HTTP_REFERER']
102
     * qui peut être défini par l'utilisateur, il n'est donc pas fiable et n'est pas défini par certains navigateurs/serveurs.
103
     *
104
     * @return \BlitzPHP\Http\Uri|mixed|string
105
     */
106
    function previous_url(bool $returnObject = false)
107
    {
108
        // Récupérez d'abord la session, si nous l'avons,
109
        // car c'est plus fiable et plus sûr.
110
        // Sinon, récupérez une version épurée de $_SERVER.
111
        $referer = $_SESSION['_blitz_previous_url'] ?? null;
112
        if (false === filter_var($referer, FILTER_VALIDATE_URL)) {
113
            $referer = Services::request()->getServer('HTTP_REFERER', FILTER_SANITIZE_URL);
0 ignored issues
show
Bug introduced by
The method getServer() does not exist on BlitzPHP\Http\Request. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

113
            $referer = Services::request()->/** @scrutinizer ignore-call */ getServer('HTTP_REFERER', FILTER_SANITIZE_URL);
Loading history...
114
        }
115
116
        $referer ??= site_url('/');
117
118
        return $returnObject ? Services::uri($referer) : $referer;
119
    }
120
}
121
122
if (! function_exists('uri_string')) {
123
    /**
124
     * Renvoie la partie chemin de l'URL actuelle
125
     *
126
     * @param bool $relative Si le chemin résultant doit être relatif à baseURL
127
     */
128
    function uri_string(bool $relative = false): string
129
    {
130
        return $relative
131
            ? ltrim(Services::request()->getPath(), '/')
132
            : Services::request()->getUri()->getPath();
133
    }
134
}
135
136
if (! function_exists('index_page')) {
137
    /**
138
     * Renvoie la "index_page" de votre fichier de configuration
139
     */
140
    function index_page(): string
141
    {
142
        return config('app.index_page');
0 ignored issues
show
Bug Best Practice introduced by
The expression return config('app.index_page') returns the type BlitzPHP\Config\Config|null which is incompatible with the type-hinted return string.
Loading history...
143
    }
144
}
145
146
if (! function_exists('anchor')) {
147
    /**
148
     * Crée une ancre basée sur l'URL locale.
149
     *
150
     * @param string             $title      le titre du lien
151
     * @param array|false|string $attributes tous les attributs
152
     * @param mixed              $uri
153
     */
154
    function anchor($uri = '', string $title = '', $attributes = ''): string
155
    {
156
        $siteUrl = is_array($uri) ? site_url($uri, null) : (preg_match('#^(\w+:)?//#i', $uri) ? $uri : site_url($uri, null));
157
        $siteUrl = rtrim($siteUrl, '/');
158
159
        if ($title === '') {
160
            $title = $siteUrl;
161
        }
162
163
        if ($attributes !== '') {
164
            $attributes = stringify_attributes($attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes can also be of type false; however, parameter $attributes of stringify_attributes() does only seem to accept array|object|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

164
            $attributes = stringify_attributes(/** @scrutinizer ignore-type */ $attributes);
Loading history...
165
        }
166
167
        return '<a href="' . $siteUrl . '"' . $attributes . '>' . $title . '</a>';
168
    }
169
}
170
171
if (! function_exists('anchor_popup')) {
172
    /**
173
     * Lien d'ancrage - Version contextuelle
174
     *
175
     * Crée une ancre basée sur l'URL locale. Le lien
176
     * ouvre une nouvelle fenêtre basée sur les attributs spécifiés.
177
     *
178
     * @param string             $title      le titre du lien
179
     * @param array|false|string $attributes tous les attributs
180
     */
181
    function anchor_popup(string $uri = '', string $title = '', $attributes = false): string
182
    {
183
        $siteUrl = preg_match('#^(\w+:)?//#i', $uri) ? $uri : site_url($uri, null);
184
        $siteUrl = rtrim($siteUrl, '/');
185
186
        if ($title === '') {
187
            $title = $siteUrl;
188
        }
189
190
        if ($attributes === false) {
191
            return '<a href="' . $siteUrl . '" onclick="window.open(\'' . $siteUrl . "', '_blank'); return false;\">" . $title . '</a>';
192
        }
193
194
        if (! is_array($attributes)) {
195
            $attributes = [$attributes];
196
197
            // Ref: http://www.w3schools.com/jsref/met_win_open.asp
198
            $windowName = '_blank';
199
        } elseif (! empty($attributes['window_name'])) {
200
            $windowName = $attributes['window_name'];
201
            unset($attributes['window_name']);
202
        } else {
203
            $windowName = '_blank';
204
        }
205
206
        foreach (['width' => '800', 'height' => '600', 'scrollbars' => 'yes', 'menubar' => 'no', 'status' => 'yes', 'resizable' => 'yes', 'screenx' => '0', 'screeny' => '0'] as $key => $val) {
207
            $atts[$key] = $attributes[$key] ?? $val;
208
            unset($attributes[$key]);
209
        }
210
211
        $attributes = stringify_attributes($attributes);
212
213
        return '<a href="' . $siteUrl
214
                . '" onclick="window.open(\'' . $siteUrl . "', '" . $windowName . "', '" . stringify_attributes($atts, true) . "'); return false;\""
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $atts seems to be defined by a foreach iteration on line 206. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
215
                . $attributes . '>' . $title . '</a>';
216
    }
217
}
218
219
if (! function_exists('mailto')) {
220
    /**
221
     * Lien Mailto
222
     *
223
     * @param string       $title      le titre du lien
224
     * @param array|string $attributes tous les attributs
225
     */
226
    function mailto(string $email, string $title = '', $attributes = ''): string
227
    {
228
        if (trim($title) === '') {
229
            $title = $email;
230
        }
231
232
        return '<a href="mailto:' . $email . '"' . stringify_attributes($attributes) . '>' . $title . '</a>';
233
    }
234
}
235
236
if (! function_exists('safe_mailto')) {
237
    /**
238
     * Lien Mailto codé
239
     *
240
     * Créer un lien mailto protégé contre les spams écrit en Javascript
241
     *
242
     * @param string $title      le titre du lien
243
     * @param mixed  $attributes tous les attributs
244
     */
245
    function safe_mailto(string $email, string $title = '', $attributes = ''): string
246
    {
247
        if (trim($title) === '') {
248
            $title = $email;
249
        }
250
251
        $x = str_split('<a href="mailto:', 1);
252
253
        for ($i = 0, $l = strlen($email); $i < $l; $i++) {
254
            $x[] = '|' . ord($email[$i]);
255
        }
256
257
        $x[] = '"';
258
259
        if ($attributes !== '') {
260
            if (is_array($attributes)) {
261
                foreach ($attributes as $key => $val) {
262
                    $x[] = ' ' . $key . '="';
263
264
                    for ($i = 0, $l = strlen($val); $i < $l; $i++) {
265
                        $x[] = '|' . ord($val[$i]);
266
                    }
267
268
                    $x[] = '"';
269
                }
270
            } else {
271
                for ($i = 0, $l = mb_strlen($attributes); $i < $l; $i++) {
272
                    $x[] = mb_substr($attributes, $i, 1);
273
                }
274
            }
275
        }
276
277
        $x[] = '>';
278
279
        $temp = [];
280
281
        for ($i = 0, $l = strlen($title); $i < $l; $i++) {
282
            $ordinal = ord($title[$i]);
283
284
            if ($ordinal < 128) {
285
                $x[] = '|' . $ordinal;
286
            } else {
287
                if (empty($temp)) {
288
                    $count = ($ordinal < 224) ? 2 : 3;
289
                }
290
291
                $temp[] = $ordinal;
292
293
                if (count($temp) === $count) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $count does not seem to be defined for all execution paths leading up to this point.
Loading history...
294
                    $number = ($count === 3) ? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64) : (($temp[0] % 32) * 64) + ($temp[1] % 64);
295
                    $x[]    = '|' . $number;
296
                    $count  = 1;
297
                    $temp   = [];
298
                }
299
            }
300
        }
301
302
        $x[] = '<';
303
        $x[] = '/';
304
        $x[] = 'a';
305
        $x[] = '>';
306
307
        $x = array_reverse($x);
0 ignored issues
show
Bug introduced by
It seems like $x can also be of type true; however, parameter $array of array_reverse() does only seem to accept array, 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

307
        $x = array_reverse(/** @scrutinizer ignore-type */ $x);
Loading history...
308
309
        // améliore l'obscurcissement en éliminant les retours à la ligne et les espaces
310
        $output = '<script type="text/javascript">'
311
                . 'var l=new Array();';
312
313
        foreach ($x as $i => $value) {
314
            $output .= 'l[' . $i . "] = '" . $value . "';";
315
        }
316
317
        return $output . ('for (var i = l.length-1; i >= 0; i=i-1) {'
318
                . "if (l[i].substring(0, 1) === '|') document.write(\"&#\"+unescape(l[i].substring(1))+\";\");"
319
                . 'else document.write(unescape(l[i]));'
320
                . '}'
321
                . '</script>');
322
    }
323
}
324
325
if (! function_exists('auto_link')) {
326
    /**
327
     * Lien automatique
328
     *
329
     * Liens automatiquement URL et adresses e-mail.
330
     * Remarque : il y a un peu de code supplémentaire ici à gérer
331
     * URL ou e-mails se terminant par un point. Nous allons les dépouiller
332
     * off et ajoutez-les après le lien.
333
     *
334
     * @param string $type  le type : email, url, ou les deux
335
     * @param bool   $popup s'il faut créer des liens contextuels
336
     */
337
    function auto_link(string $str, string $type = 'both', bool $popup = false): string
338
    {
339
        // Recherche et remplace tous les URLs.
340
        if ($type !== 'email' && preg_match_all('#(\w*://|www\.)[^\s()<>;]+\w#i', $str, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
341
            // Définissez notre HTML cible si vous utilisez des liens contextuels.
342
            $target = ($popup) ? ' target="_blank"' : '';
343
344
            // Nous traitons les liens dans l'ordre inverse (dernier -> premier) de sorte que
345
            // les décalages de chaîne renvoyés par preg_match_all() ne sont pas
346
            // déplacées au fur et à mesure que nous ajoutons plus de HTML.
347
            foreach (array_reverse($matches) as $match) {
348
                // $match[0] est la chaîne/le lien correspondant
349
                // $match[1] est soit un préfixe de protocole soit 'www.'
350
                //
351
                // Avec PREG_OFFSET_CAPTURE, les deux éléments ci-dessus sont un tableau,
352
                // où la valeur réelle est contenue dans [0] et son décalage à l'index [1].
353
                $a   = '<a href="' . (strpos($match[1][0], '/') ? '' : 'http://') . $match[0][0] . '"' . $target . '>' . $match[0][0] . '</a>';
354
                $str = substr_replace($str, $a, $match[0][1], strlen($match[0][0]));
355
            }
356
        }
357
358
        // Recherche et remplace tous les e-mails.
359
        if ($type !== 'url' && preg_match_all('#([\w\.\-\+]+@[a-z0-9\-]+\.[a-z0-9\-\.]+[^[:punct:]\s])#i', $str, $matches, PREG_OFFSET_CAPTURE)) {
0 ignored issues
show
Unused Code introduced by
The call to preg_match_all() has too many arguments starting with PREG_OFFSET_CAPTURE. ( Ignorable by Annotation )

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

359
        if ($type !== 'url' && /** @scrutinizer ignore-call */ preg_match_all('#([\w\.\-\+]+@[a-z0-9\-]+\.[a-z0-9\-\.]+[^[:punct:]\s])#i', $str, $matches, PREG_OFFSET_CAPTURE)) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
360
            foreach (array_reverse($matches[0]) as $match) {
361
                if (filter_var($match[0], FILTER_VALIDATE_EMAIL) !== false) {
362
                    $str = substr_replace($str, safe_mailto($match[0]), $match[1], strlen($match[0]));
363
                }
364
            }
365
        }
366
367
        return $str;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $str could return the type array which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
368
    }
369
}
370
371
if (! function_exists('prep_url')) {
372
    /**
373
     * Ajoute simplement la partie http:// ou https:// si aucun schéma n'est inclus.
374
     *
375
     * @param bool $secure définissez true si vous voulez forcer https://
376
     */
377
    function prep_url(string $str = '', bool $secure = false): string
378
    {
379
        if (in_array($str, ['http://', 'https://', '//', ''], true)) {
380
            return '';
381
        }
382
383
        if (parse_url($str, PHP_URL_SCHEME) === null) {
384
            $str = 'http://' . ltrim($str, '/');
385
        }
386
387
        // force le remplacement de http:// par https://
388
        if ($secure) {
389
            $str = preg_replace('/^(?:http):/i', 'https:', $str);
390
        }
391
392
        return $str;
393
    }
394
}
395
396
if (! function_exists('url_title')) {
397
    /**
398
     * Créer un titre d'URL
399
     *
400
     * Prend une chaîne de "titre" en entrée et crée un
401
     * Chaîne d'URL conviviale avec une chaîne de "séparateur"
402
     * comme séparateur de mots.
403
     *
404
     * @param string $separator Séparateur de mots (généralement '-' ou '_')
405
     * @param bool   $lowercase Indique s'il faut transformer la chaîne de sortie en minuscules
406
     */
407
    function url_title(string $str, string $separator = '-', bool $lowercase = false): string
408
    {
409
        $qSeparator = preg_quote($separator, '#');
410
411
        $trans = [
412
            '&.+?;'                  => '',
413
            '[^\w\d\pL\pM _-]'       => '',
414
            '\s+'                    => $separator,
415
            '(' . $qSeparator . ')+' => $separator,
416
        ];
417
418
        $str = strip_tags($str);
419
420
        foreach ($trans as $key => $val) {
421
            $str = preg_replace('#' . $key . '#iu', $val, $str);
422
        }
423
424
        if ($lowercase === true) {
425
            $str = mb_strtolower($str);
426
        }
427
428
        return trim(trim($str, $separator));
429
    }
430
}
431
432
if (! function_exists('mb_url_title')) {
433
    /**
434
     * Créer un titre d'URL qui prend en compte les caractères accentués
435
     *
436
     * Prend une chaîne de "titre" en entrée et crée un
437
     * Chaîne d'URL conviviale avec une chaîne de "séparateur"
438
     * comme séparateur de mots.
439
     *
440
     * @param string $separator Séparateur de mots (généralement '-' ou '_')
441
     * @param bool   $lowercase Indique s'il faut transformer la chaîne de sortie en minuscules
442
     */
443
    function mb_url_title(string $str, string $separator = '-', bool $lowercase = false): string
444
    {
445
        helper('text');
446
447
        return url_title(convert_accented_characters($str), $separator, $lowercase);
0 ignored issues
show
Bug introduced by
The function convert_accented_characters was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

447
        return url_title(/** @scrutinizer ignore-call */ convert_accented_characters($str), $separator, $lowercase);
Loading history...
448
    }
449
}
450
451
if (! function_exists('route')) {
452
    /**
453
     * Générez l'URL vers une route nommée.
454
     * 
455
     * @param mixed ...$params
456
     *
457
     * @throws RouterException
458
     */
459
    function route(string $name, ...$params): string
460
    {
461
        if (config('app.prefere-route-method') === 'url_to') {
0 ignored issues
show
introduced by
The condition config('app.prefere-route-method') === 'url_to' is always false.
Loading history...
462
            return url_to($name, ...$params);
463
        }
464
465
        return link_to($name, ...$params);
466
    }
467
}
468
469
if (! function_exists('url_to')) {
470
    /**
471
     * Obtenir l'URL complète et absolue d'une méthode de contrôleur
472
     * (avec arguments supplémentaires)
473
     *
474
     * REMARQUE : Cela nécessite que le contrôleur/la méthode ait une route définie dans le fichier de configuration des routes.
475
     *
476
     * @param mixed ...$args
477
     *
478
     * @throws RouterException
479
     */
480
    function url_to(string $controller, ...$args): string
481
    {
482
        if (! $route = link_to($controller, ...$args)) {
483
            $explode = explode('::', $controller);
484
485
            if (isset($explode[1])) {
486
                throw RouterException::controllerNotFound($explode[0], $explode[1]);
487
            }
488
489
            throw RouterException::invalidRoute($controller);
490
        }
491
492
        return site_url($route);
493
    }
494
}
495
496
if (! function_exists('url_is')) {
497
    /**
498
     * Détermine si le chemin d'URL actuel contient le chemin donné.
499
     * Il peut contenir un caractère générique (*) qui autorisera tout caractère valide.
500
     *
501
     * Exemple:
502
     *   if (url_is('admin*)) ...
503
     */
504
    function url_is(string $path): bool
505
    {
506
        // Configurez notre regex pour autoriser les caractères génériques
507
        $path        = '/' . trim(str_replace('*', '(\S)*', $path), '/ ');
508
        $currentPath = '/' . trim(uri_string(true), '/ ');
509
510
        return (bool) preg_match("|^{$path}$|", $currentPath, $matches);
511
    }
512
}
513
514
if (! function_exists('link_active')) {
515
    /**
516
     * Lien actif dans la navbar
517
     * Un peut comme le router-active-link de vuejs
518
     */
519
    function link_active(string $path, string $active_class = 'active', bool $exact = false): string
520
    {
521
        $current_url     = trim(current_url(false), '/');
522
        $current_section = trim(str_replace(trim(site_url(), '/'), '', $current_url), '/');
523
524
        if ($current_section === $path) {
525
            return $active_class;
526
        }
527
528
        if (! $exact && preg_match('#^' . $path . '/?#i', $current_section)) {
529
            return $active_class;
530
        }
531
532
        if (trim(link_to($path), '/') === $current_url) {
533
            return $active_class;
534
        }
535
536
        return '';
537
    }
538
}
539
540
if (! function_exists('clean_url')) {
541
    function clean_url(string $url): string
542
    {
543
        return Helpers::cleanUrl($url);
544
    }
545
}
546
547
if (! function_exists('is_absolute_link')) {
548
    /**
549
     * Verifies si un chemin donnée est une url absolue ou relative
550
     */
551
    function is_absolute_link(string $url): string
552
    {
553
        return Helpers::isAbsoluteUrl($url);
0 ignored issues
show
Bug Best Practice introduced by
The expression return BlitzPHP\Utilitie...rs::isAbsoluteUrl($url) returns the type boolean which is incompatible with the type-hinted return string.
Loading history...
554
    }
555
}
556