Passed
Push — main ( 073c01...b49c3d )
by Dimitri
03:21
created

link_active()   B

Complexity

Conditions 9
Paths 7

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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

62
        /** @scrutinizer ignore-call */ 
63
        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...
63
64
        $url = rtrim(site_url($relativePath, $scheme), '/');
65
        config('app.index_page', $index_page, true);
66
67
        return $url;
68
    }
69
}
70
71
if (! function_exists('current_url')) {
72
    /**
73
     * Renvoie l'URL complète (y compris les segments) de la page où cette fonction est placée
74
     *
75
     * @param bool $returnObject True pour renvoyer un objet au lieu d'une chaîne
76
     *
77
     * @return \BlitzPHP\Http\Uri|string
78
     */
79
    function current_url(bool $returnObject = false, ?ServerRequest $request = null)
80
    {
81
        $request ??= Services::request();
82
        $path = $request->getPath();
83
84
        // Ajouter des chaine de requêtes et des fragments
85
        if ($query = $request->getUri()->getQuery()) {
86
            $path .= '?' . $query;
87
        }
88
        if ($fragment = $request->getUri()->getFragment()) {
89
            $path .= '#' . $fragment;
90
        }
91
92
        $uri = App::getUri($path);
93
94
        return $returnObject ? $uri : Uri::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath());
95
    }
96
}
97
98
if (! function_exists('previous_url')) {
99
    /**
100
     * Renvoie l'URL précédente sur laquelle se trouvait le visiteur actuel. Pour des raisons de sécurité
101
     * nous vérifions d'abord une variable de session enregistrée, si elle existe, et l'utilisons.
102
     * Si ce n'est pas disponible, cependant, nous utiliserons une URL épurée de $_SERVER['HTTP_REFERER']
103
     * qui peut être défini par l'utilisateur, il n'est donc pas fiable et n'est pas défini par certains navigateurs/serveurs.
104
     *
105
     * @return \BlitzPHP\Http\Uri|mixed|string
106
     */
107
    function previous_url(bool $returnObject = false)
108
    {
109
		/** @var UrlGenerator $generator */
110
		$generator = service(UrlGenerator::class);
111
112
		$referer = $generator->previous();
113
114
        return $returnObject ? Services::uri($referer) : $referer;
115
    }
116
}
117
118
if (! function_exists('uri_string')) {
119
    /**
120
     * Renvoie la partie chemin de l'URL actuelle
121
     *
122
     * @param bool $relative Si le chemin résultant doit être relatif à baseURL
123
     */
124
    function uri_string(bool $relative = false): string
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...
125
    {
126
        return $relative
127
            ? ltrim(Services::request()->getPath(), '/')
128
            : Services::request()->getUri()->getPath();
129
    }
130
}
131
132
if (! function_exists('index_page')) {
133
    /**
134
     * Renvoie la "index_page" de votre fichier de configuration
135
     */
136
    function index_page(): string
137
    {
138
        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...
139
    }
140
}
141
142
if (! function_exists('anchor')) {
143
    /**
144
     * Crée une ancre basée sur l'URL locale.
145
     *
146
     * @param string             $title      le titre du lien
147
     * @param array|false|string $attributes tous les attributs
148
     * @param mixed              $uri
149
     */
150
    function anchor($uri = '', string $title = '', $attributes = ''): string
151
    {
152
        $siteUrl = is_array($uri) ? site_url($uri, null) : (preg_match('#^(\w+:)?//#i', $uri) ? $uri : site_url($uri, null));
153
        $siteUrl = rtrim($siteUrl, '/');
154
155
        if ($title === '') {
156
            $title = $siteUrl;
157
        }
158
159
        if ($attributes !== '') {
160
            $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

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

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

355
        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...
356
            foreach (array_reverse($matches[0]) as $match) {
357
                if (filter_var($match[0], FILTER_VALIDATE_EMAIL) !== false) {
358
                    $str = substr_replace($str, safe_mailto($match[0]), $match[1], strlen($match[0]));
359
                }
360
            }
361
        }
362
363
        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...
364
    }
365
}
366
367
if (! function_exists('prep_url')) {
368
    /**
369
     * Ajoute simplement la partie http:// ou https:// si aucun schéma n'est inclus.
370
     *
371
     * @param bool $secure définissez true si vous voulez forcer https://
372
     */
373
    function prep_url(string $str = '', bool $secure = false): string
374
    {
375
        if (in_array($str, ['http://', 'https://', '//', ''], true)) {
376
            return '';
377
        }
378
379
        if (parse_url($str, PHP_URL_SCHEME) === null) {
380
            $str = 'http://' . ltrim($str, '/');
381
        }
382
383
        // force le remplacement de http:// par https://
384
        if ($secure) {
385
            $str = preg_replace('/^(?:http):/i', 'https:', $str);
386
        }
387
388
        return $str;
389
    }
390
}
391
392
if (! function_exists('url_title')) {
393
    /**
394
     * Créer un titre d'URL
395
     *
396
     * Prend une chaîne de "titre" en entrée et crée un
397
     * Chaîne d'URL conviviale avec une chaîne de "séparateur"
398
     * comme séparateur de mots.
399
     *
400
     * @param string $separator Séparateur de mots (généralement '-' ou '_')
401
     * @param bool   $lowercase Indique s'il faut transformer la chaîne de sortie en minuscules
402
     */
403
    function url_title(string $str, string $separator = '-', bool $lowercase = false): string
404
    {
405
        $qSeparator = preg_quote($separator, '#');
406
407
        $trans = [
408
            '&.+?;'                  => '',
409
            '[^\w\d\pL\pM _-]'       => '',
410
            '\s+'                    => $separator,
411
            '(' . $qSeparator . ')+' => $separator,
412
        ];
413
414
        $str = strip_tags($str);
415
416
        foreach ($trans as $key => $val) {
417
            $str = preg_replace('#' . $key . '#iu', $val, $str);
418
        }
419
420
        if ($lowercase === true) {
421
            $str = mb_strtolower($str);
422
        }
423
424
        return trim(trim($str, $separator));
425
    }
426
}
427
428
if (! function_exists('mb_url_title')) {
429
    /**
430
     * Créer un titre d'URL qui prend en compte les caractères accentués
431
     *
432
     * Prend une chaîne de "titre" en entrée et crée un
433
     * Chaîne d'URL conviviale avec une chaîne de "séparateur"
434
     * comme séparateur de mots.
435
     *
436
     * @param string $separator Séparateur de mots (généralement '-' ou '_')
437
     * @param bool   $lowercase Indique s'il faut transformer la chaîne de sortie en minuscules
438
     */
439
    function mb_url_title(string $str, string $separator = '-', bool $lowercase = false): string
440
    {
441
        helper('text');
442
443
        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

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