-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
Description
Description
Summary
This RFC proposes adding object sanitization capabilities to the Symfony HtmlSanitizer component, allowing developers to automatically sanitize string properties of objects using a simple PHP attribute.
Motivation
Currently, the HtmlSanitizer component only supports sanitizing individual strings. In real-world applications, developers often work with domain objects (entities, DTOs, form models) that contain multiple string properties requiring HTML sanitization.
Current approach requires:
$user->name = $htmlSanitizer->sanitize($user->name);
$user->bio = $htmlSanitizer->sanitize($user->bio);
$user->description = $htmlSanitizer->sanitize($user->description);
// ... repeat for each property
Problems with the current approach:
- Repetitive and error-prone code
- Easy to forget sanitizing some properties
- No declarative way to mark which properties need sanitization
- Difficult to maintain when object structure changes
Proposal
Add a new #[Sanitize]
attribute and a sanitizeObject()
method to the HtmlSanitizer
class, enabling declarative, automatic sanitization of object properties.
API Design
1. New Attribute: Sanitize
namespace Symfony\Component\HtmlSanitizer\Attribute;
#[\Attribute(\Attribute::TARGET_PROPERTY)]
final class Sanitize
{
}
2. New Method: sanitizeObject()
Added to HtmlSanitizerInterface
:
public function sanitizeObject(object $object): object;
Implementation Details
Core Behavior:
- Uses Reflection to find all properties annotated with
#[Sanitize]
- Validates at runtime that only string properties are annotated
- Applies
sanitizeFor(W3CReference::CONTEXT_BODY, $value)
to each annotated string property - Throws
LogicException
if#[Sanitize]
is applied to non-string properties - Safely skips uninitialized properties
Type Safety:
class Product
{
#[Sanitize]
public int $price; // ❌ Throws LogicException
#[Sanitize]
public string $description; // ✅ Valid
}
Error message:
LogicException: The #[Sanitize] attribute can only be applied to string properties.
Property 'price' in Product is of type 'integer'.
More details
-
No recursion/nested objects: Keeps the API simple and predictable. Developers can call
sanitizeObject()
explicitly on nested objects if needed. -
No caching: Validation depends on runtime values, making caching unsafe across different instances.
-
Strict validation: Throws exceptions for misuse rather than silently skipping, following Symfony's fail-fast philosophy.
-
String properties only: Clear, explicit contract that prevents confusion about what gets sanitized.
Example
use Symfony\Component\HtmlSanitizer\Attribute\Sanitize;
class User
{
#[Sanitize]
public string $name;
#[Sanitize]
public string $bio;
public string $email; // Not sanitized
public int $age; // Not sanitized
}
$user = new User();
$user->name = '<script>alert("xss")</script>John';
$user->bio = '<b>Developer</b> at <script>Company</script>';
$user->email = 'john@example.com';
$htmlSanitizer->sanitizeObject($user);
// Result:
// $user->name = 'John'
// $user->bio = '<b>Developer</b> at Company'
// $user->email = 'john@example.com' (unchanged)