safe_mailto()   D
last analyzed

Complexity

Conditions 15
Paths 264

Size

Total Lines 79
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 240

Importance

Changes 0
Metric Value
cc 15
eloc 47
c 0
b 0
f 0
nc 264
nop 3
dl 0
loc 79
ccs 0
cts 31
cp 0
crap 240
rs 4.2833

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Core\App;
13
use BlitzPHP\Exceptions\RouterException;
14
use BlitzPHP\Http\ServerRequest;
15
use BlitzPHP\Http\Uri;
16
use BlitzPHP\Http\UrlGenerator;
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('url')) {
28
    /**
29
     * Générer une url pour l'application.
30
     *
31
     * @return string|UrlGenerator
32
     */
33
    function url(?string $path = null, mixed $parameters = [], ?bool $secure = null)
34
    {
35
        /** @var UrlGenerator $generator */
36
        $generator = service(UrlGenerator::class);
37
38
        if (null === $path) {
39
            return $generator;
40
        }
41
42
        return $generator->to($path, $parameters, $secure);
43
    }
44
}
45
46
if (! function_exists('site_url')) {
47
    /**
48
     * Renvoie une URL de site telle que définie par la configuration de l'application.
49
     *
50
     * @param mixed $relativePath Chaîne d'URI ou tableau de segments d'URI
51
     */
52
    function site_url($relativePath = '', ?string $scheme = null): string
53
    {
54
        if (is_array($relativePath)) {
55 6
            $relativePath = implode('/', $relativePath);
56
        }
57
58 6
        $uri = App::getUri($relativePath);
59
60
        return Uri::createURIString(
61
            $scheme ?? $uri->getScheme(),
62
            $uri->getAuthority(),
63
            $uri->getPath(),
64
            $uri->getQuery(),
65
            $uri->getFragment()
66 6
        );
67
    }
68
}
69
70
if (! function_exists('base_url')) {
71
    /**
72
     * Renvoie l'URL de base telle que définie par la configuration de l'application.
73
     * Les URL de base sont des URL de site coupées sans la page d'index.
74
     *
75
     * @param mixed $relativePath Chaîne d'URI ou tableau de segments d'URI
76
     */
77
    function base_url($relativePath = '', ?string $scheme = null): string
78
    {
79
        $index_page = index_page();
80
        config()->set('app.index_page', '');
81
82
        $url = rtrim(site_url($relativePath, $scheme), '/');
83
        config()->set('app.index_page', $index_page);
84
85
        return $url;
86
    }
87
}
88
89
if (! function_exists('current_url')) {
90
    /**
91
     * Renvoie l'URL complète (y compris les segments) de la page où cette fonction est placée
92
     *
93
     * @param bool $returnObject True pour renvoyer un objet au lieu d'une chaîne
94
     *
95
     * @return string|Uri
96
     */
97
    function current_url(bool $returnObject = false, ?ServerRequest $request = null)
98
    {
99
        $request ??= service('request');
100
        $path = $request->getPath();
101
102
        // Ajouter des chaine de requêtes et des fragments
103
        if (($query = $request->getUri()->getQuery()) !== '') {
104
            $path .= '?' . $query;
105
        }
106
        if (($fragment = $request->getUri()->getFragment()) !== '') {
107
            $path .= '#' . $fragment;
108
        }
109
110
        $uri = App::getUri($path);
111
112
        return $returnObject ? $uri : Uri::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath());
113
    }
114
}
115
116
if (! function_exists('previous_url')) {
117
    /**
118
     * Renvoie l'URL précédente sur laquelle se trouvait le visiteur actuel. Pour des raisons de sécurité
119
     * nous vérifions d'abord une variable de session enregistrée, si elle existe, et l'utilisons.
120
     * Si ce n'est pas disponible, cependant, nous utiliserons une URL épurée de $_SERVER['HTTP_REFERER']
121
     * qui peut être défini par l'utilisateur, il n'est donc pas fiable et n'est pas défini par certains navigateurs/serveurs.
122
     *
123
     * @return mixed|string|Uri
124
     */
125
    function previous_url(bool $returnObject = false)
126
    {
127
        $referer = url()->previous();
128
129
        return $returnObject ? service('uri', $referer) : $referer;
130
    }
131
}
132
133
if (! function_exists('uri_string')) {
134
    /**
135
     * Renvoie la partie chemin de l'URL actuelle
136
     *
137
     * @param bool $relative Si le chemin résultant doit être relatif à baseURL
138
     */
139
    function uri_string(bool $relative = false): string
140
    {
141
        return $relative
142
            ? ltrim(service('request')->getPath(), '/')
143
            : service('request')->getUri()->getPath();
144
    }
145
}
146
147
if (! function_exists('index_page')) {
148
    /**
149
     * Renvoie la "index_page" de votre fichier de configuration
150
     */
151
    function index_page(): string
152
    {
153
        return config('app.index_page');
0 ignored issues
show
Bug Best Practice introduced by
The expression return config('app.index_page') could return the type null|object which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
154
    }
155
}
156
157
if (! function_exists('anchor')) {
158
    /**
159
     * Crée une ancre basée sur l'URL locale.
160
     *
161
     * @param string             $title      le titre du lien
162
     * @param array|false|string $attributes tous les attributs
163
     * @param mixed              $uri
164
     */
165
    function anchor($uri = '', string $title = '', $attributes = ''): string
166
    {
167
        $siteUrl = is_array($uri) ? site_url($uri, null) : (preg_match('#^(\w+:)?//#i', $uri) ? $uri : site_url($uri, null));
168
        $siteUrl = rtrim($siteUrl, '/');
169
170
        if ($title === '') {
171
            $title = $siteUrl;
172
        }
173
174
        if ($attributes !== '') {
175
            $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

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

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

374
        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...
375
            foreach (array_reverse($matches[0]) as $match) {
376
                if (filter_var($match[0], FILTER_VALIDATE_EMAIL) !== false) {
377
                    $str = substr_replace($str, safe_mailto($match[0]), $match[1], strlen($match[0]));
378
                }
379
            }
380
        }
381
382
        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...
383
    }
384
}
385
386
if (! function_exists('prep_url')) {
387
    /**
388
     * Ajoute simplement la partie http:// ou https:// si aucun schéma n'est inclus.
389
     *
390
     * @param bool $secure définissez true si vous voulez forcer https://
391
     */
392
    function prep_url(string $str = '', bool $secure = false): string
393
    {
394
        if (in_array($str, ['http://', 'https://', '//', ''], true)) {
395
            return '';
396
        }
397
398
        if (parse_url($str, PHP_URL_SCHEME) === null) {
399
            $str = 'http://' . ltrim($str, '/');
400
        }
401
402
        // force le remplacement de http:// par https://
403
        if ($secure) {
404
            $str = preg_replace('/^(?:http):/i', 'https:', $str);
405
        }
406
407
        return $str;
408
    }
409
}
410
411
if (! function_exists('url_title')) {
412
    /**
413
     * Créer un titre d'URL
414
     *
415
     * Prend une chaîne de "titre" en entrée et crée un
416
     * Chaîne d'URL conviviale avec une chaîne de "séparateur"
417
     * comme séparateur de mots.
418
     *
419
     * @param string $separator Séparateur de mots (généralement '-' ou '_')
420
     * @param bool   $lowercase Indique s'il faut transformer la chaîne de sortie en minuscules
421
     */
422
    function url_title(string $str, string $separator = '-', bool $lowercase = false): string
423
    {
424
        $qSeparator = preg_quote($separator, '#');
425
426
        $trans = [
427
            '&.+?;'                  => '',
428
            '[^\w\d\pL\pM _-]'       => '',
429
            '\s+'                    => $separator,
430
            '(' . $qSeparator . ')+' => $separator,
431
        ];
432
433
        $str = strip_tags($str);
434
435
        foreach ($trans as $key => $val) {
436
            $str = preg_replace('#' . $key . '#iu', $val, $str);
437
        }
438
439
        if ($lowercase === true) {
440
            $str = mb_strtolower($str);
441
        }
442
443
        return trim(trim($str, $separator));
444
    }
445
}
446
447
if (! function_exists('mb_url_title')) {
448
    /**
449
     * Créer un titre d'URL qui prend en compte les caractères accentués
450
     *
451
     * Prend une chaîne de "titre" en entrée et crée un
452
     * Chaîne d'URL conviviale avec une chaîne de "séparateur"
453
     * comme séparateur de mots.
454
     *
455
     * @param string $separator Séparateur de mots (généralement '-' ou '_')
456
     * @param bool   $lowercase Indique s'il faut transformer la chaîne de sortie en minuscules
457
     */
458
    function mb_url_title(string $str, string $separator = '-', bool $lowercase = false): string
459
    {
460
        helper('scl');
461
462
        return url_title(scl_moveSpecialChar($str), $separator, $lowercase);
463
    }
464
}
465
466
if (! function_exists('url_to')) {
467
    /**
468
     * Obtenir l'URL complète et absolue d'une méthode de contrôleur
469
     * (avec arguments supplémentaires)
470
     *
471
     * REMARQUE : Cela nécessite que le contrôleur/la méthode ait une route définie dans le fichier de configuration des routes.
472
     *
473
     * @param mixed ...$args
474
     *
475
     * @throws RouterException
476
     */
477
    function url_to(string $controller, ...$args): string
478
    {
479
        if (! $route = route($controller, ...$args)) {
480
            $explode = explode('::', $controller);
481
482
            if (isset($explode[1])) {
483
                throw RouterException::controllerNotFound($explode[0], $explode[1]);
484
            }
485
486
            throw RouterException::invalidRoute($controller);
487
        }
488
489
        return site_url($route);
490
    }
491
}
492
493
if (! function_exists('route')) {
494
    /**
495
     * Tente de rechercher une route en fonction de sa destination.
496
     *
497
     * @return false|string
498
     */
499
    function route(string $method, ...$params)
500
    {
501
        return service('routes')->reverseRoute($method, ...$params);
502
    }
503
}
504
505
if (! function_exists('action')) {
506
    /**
507
     * Obtenir l'URL d'une action du contrôleur.
508
     *
509
     * @return false|string
510
     */
511
    function action(array|string $action, array $parameters = [])
512
    {
513
        return url()->action($action, $parameters);
514
    }
515
}
516
517
if (! function_exists('url_is')) {
518
    /**
519
     * Détermine si le chemin d'URL actuel contient le chemin donné.
520
     * Il peut contenir un caractère générique (*) qui autorisera tout caractère valide.
521
     *
522
     * Exemple:
523
     *   if (url_is('admin*)) ...
524
     */
525
    function url_is(string $path): bool
526
    {
527
        // Configurez notre regex pour autoriser les caractères génériques
528
        $path        = '/' . trim(str_replace('*', '(\S)*', $path), '/ ');
529
        $currentPath = '/' . trim(uri_string(true), '/ ');
530
531
        return (bool) preg_match("|^{$path}$|", $currentPath, $matches);
532
    }
533
}
534
535
if (! function_exists('link_active')) {
536
    /**
537
     * Lien actif dans la navbar
538
     * Un peut comme le router-active-link de vuejs
539
     */
540
    function link_active(array|string $path, string $active_class = 'active', bool $exact = false): string
541
    {
542
        if (is_array($path)) {
0 ignored issues
show
introduced by
The condition is_array($path) is always true.
Loading history...
543
            foreach ($path as $p) {
544
                if ($active_class === link_active($p, $active_class, $exact)) {
545
                    return $active_class;
546
                }
547
            }
548
549
            return '';
550
        }
551
552
        $current_url     = trim(current_url(false), '/');
553
        $current_section = trim(str_replace(trim(site_url(), '/'), '', $current_url), '/');
554
555
        if ($current_section === $path || $current_url === $path) {
556
            return $active_class;
557
        }
558
559
        if (! $exact && preg_match('#^' . $path . '/?#i', $current_section)) {
560
            return $active_class;
561
        }
562
563
        if (trim(link_to($path), '/') === $current_url) {
564
            return $active_class;
565
        }
566
567
        return '';
568
    }
569
}
570
571
if (! function_exists('clean_url')) {
572
    function clean_url(string $url): string
573
    {
574
        return Helpers::cleanUrl($url);
575
    }
576
}
577
578
if (! function_exists('is_absolute_link')) {
579
    /**
580
     * Verifies si un chemin donnée est une url absolue ou relative
581
     */
582
    function is_absolute_link(string $url): bool
583
    {
584
        return Helpers::isAbsoluteUrl($url);
585
    }
586
}
587