#1
Ahoy!,

An update has been made to the anchor() function, and this post will walk through what’s new, why the change was implemented, and why it shouldn’t raise security concerns. The goal remains to improve the framework without introducing breaking changes. This update should not be a breaking change, but please read on to confirm.

WHAT HAS CHANGED?

The anchor() function has been simplified by removing its attempt to automatically escape the $text parameter (the inner text of the link). Previously, it tried to detect HTML in $text (e.g., <i> tags) and only escaped it if no HTML was present. Now, $text is left unescaped by default, while $url and $attributes remain safely escaped to prevent XSS attacks.

The updated recommendation is to pair anchor() with the out() function when handling user-generated content. For example:



The documentation has been updated to reflect this change, including examples and security guidance.

Check it out here:

https://trongate.io/documentation/display/php_framework/helpers-explained/other-helpful-features

WHY THESE CHANGES WERE MADE

The original anchor() function had a weakness: its conditional escaping logic (checking for < in $text) was inconsistent and not a robust way to handle security. It tried to be “smart” by guessing when to escape, but this half-measure could give a false sense of safety while still leaving gaps. Additionally, challenges arose with HTML entities erroneously appearing in rendered link text.

WHY THE NEW APPROACH IS BETTER

By removing the escaping logic, anchor() now focuses on one job—building an anchor tag with a safe URL and attributes. It no longer attempts to manage $text security, making its behavior predictable.
This approach isn’t controversial or even original. The updated anchor() function aligns with how similar functions work in other PHP frameworks, like CodeIgniter.

Shifting escaping responsibility to the caller also eliminates ambiguity. Developers decide how to sanitize $text, which is safer than relying on a flawed built-in guess.

In short, this change makes anchor() leaner, more transparent, and less likely to mislead developers into thinking it’s a one-stop security solution.

WHY THIS ISN’T NECESSARILY A SECURITY RISK

Some might wonder if leaving $text unescaped introduces new risks. In practical terms, this change isn’t expected to have significant security implications for most real-world scenarios. Here’s why:

User-Generated Links Are Already Risky: The biggest security concern with links often comes from the $url itself (e.g., phishing or malicious redirects), not the inner text. Since anchor() still escapes $url, that vector remains protected. Allowing unvetted users to post links is a broader issue that developers should address regardless of this function.

Inner Text Rarely Executes: Modern browsers treat <a> tag content as text or markup, not executable code, unless it’s misused elsewhere (e.g., via innerHTML). The original escaping didn’t fully prevent XSS anyway - it was too weak to stop determined attacks.

Control Lies with Developers: If user input is passed to $text, it should already be sanitized (e.g., with out()). This change simply makes that requirement explicit. If sanitization wasn’t happening before, the old anchor() wasn’t offering much protection due to its limitations.

In practice, this update shouldn’t increase risk if good coding habits are followed. It might even reduce risk by removing a false sense of security and encouraging deliberate sanitization where it matters.

FINAL THOUGHTS

This update makes anchor() more reliable and easier to use correctly. Speaking a little more broadly, I think it's a good practice to give your functions simple and single tasks. It makes your code more robust and more stable. So, this latest updates moves us in that direction - and that's a good thing!

If there are questions, concerns, or feedback about how this affects your projects, feel free to chime in below. I’d love to hear your thoughts!

Cheers,

DC