XOOPS/XoopsCore25

Display problems

Closed this issue · 6 comments

The switch to smarty 3 on the monxoops.fr website is not going very well. On this site, our articles and tutorials are formatted using html.
For example, this page:

https://www.monxoops.fr/modules/xmtutorial/tutorial.php?tutorial_id=19&page_id=100#page_page

Before, the display was:

image

And now:

image

I have the impression that it's a problem in the interpretation of line breaks.
It's a major problem.

Yes, that's it! It seems that smarty 3 transforms a line break into a line feed (<br />).
My code in my tuto:

<span class="fas fa-bug mx-2 text-warning"></span> block id</button></h2>
<div id="accordion-blockid"

the generated code:
<span class="fas fa-bug mx-2 text-warning"></span> block id</button></h2><br /><div id="accordion-blockid"

I've done some research and the problem is with the file:
module.textsanitizer.php. If I put the old file, the display is normal! A change here will break the display.

Okay, I understand the problem. I used mambax7's file here:
https://github.com/mambax7/XoopsCore25/blob/feature/2512/htdocs/class/module.textsanitizer.php
The bug has been introduced in this file to try to fix this bug:
#1468
The problem comes from the "public function makeClickable($text)" function. This line should not be added:
$text = nl2br($text);

Try this code:

    protected function makeClickableCallbackEmailAddress($match)
    {
        $email = $match[2];  // Extract the email address
        return $match[1] . '<a href="mailto:' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '">' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '</a>';
    }
    
       public function makeClickable($text) {
        // Decode HTML entities
        $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');

        // Convert line breaks and multiple spaces to a single space
        $text = preg_replace('/[\n\s]+/', ' ', $text);

        // Convert email addresses into clickable mailto links
        $pattern = "/(^|[\s\n]|<br\s*\/?>)([-_a-z0-9\'+*$^&%=~!?{}]+(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*@[-a-z0-9.]+\.[a-z]{2,6})/i";
        $text = preg_replace_callback($pattern, [$this, 'makeClickableCallbackEmailAddress'], $text);

        // Convert URLs into clickable links, allowing for angle brackets, file paths, and custom protocols
        $pattern = "/(?:\s|^|[\(\[\{>])(<)?((https?:\/\/|s?ftp:\/\/|file:\/\/|custom:\/\/|www\.)[^\s<>\(\)\[\]]+[^\s<>\(\)\[\]\.,!\"'\(\)\[\]{}<>])(?<![\.,!\"'\(\)\[\]{}])/";
        $text = preg_replace_callback(
            $pattern,
            function ($matches) {
                $url = $matches[2];
                $prefix = $matches[0][0] ?? ''; // Get the prefix character (space, bracket, etc.)
                $openingBracket = $matches[1] ?? ''; // Check for the opening angle bracket

                // Ensure the URL is not a javascript: URL
                if (stripos($url, 'javascript:') === 0) {
                    return $matches[0];
                }

                // Add http prefix if missing
                if (strpos($url, 'www.') === 0) {
                    $url = "http://" . $url;
                }

                // Allow only specific protocols
                $allowedProtocols = ['http://', 'https://', 'ftp://', 'sftp://', 'file://', 'custom://'];
                $protocolAllowed = false;
                foreach ($allowedProtocols as $protocol) {
                    if (strpos($url, $protocol) === 0) {
                        $protocolAllowed = true;
                        break;
                    }
                }
                if (!$protocolAllowed) {
                    return $matches[0];
                }

                // Check if the URL is already inside an anchor tag, specifically looking for href attribute
                if (!preg_match('#<a\s[^>]*href\s*=\s*(["\'])' . preg_quote($url, '/') . '\\1[^>]*>#i', $url)) { // <-- Change here!
                    $relAttr = (strpos($url, 'ftp://') === 0 || strpos($url, 'sftp://') === 0 || strpos($url, 'file://') === 0 || strpos($url, 'custom://') === 0) ? 'external' : 'external noopener nofollow';
                    return $prefix . $openingBracket . '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="' . $relAttr . '">' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '</a>';
                }

                return $matches[0]; // Return the original match if it's already an anchor tag
            },
            $text
        );

        return $text;
    }

and let me know if it works

It works too!

If it works, can you close it?