Delete dead helpers/OutputHelper.php (#54)
Zero callers anywhere in the app — confirmed via grep for "OutputHelper::" across the whole codebase. Every view actually calls htmlspecialchars() directly instead, which a prior audit confirmed is done consistently, so escaping was never actually at risk. This was just a misleading, unused class that README.md's file reference implied was part of the app's active XSS-prevention story. Removed the file and its README Project Structure entry. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MGDKHiU5RJdo3dqQUDow3X
This commit is contained in:
@@ -362,7 +362,6 @@ tinker_tickets/
|
|||||||
│ ├── Database.php # Centralized mysqli connection
|
│ ├── Database.php # Centralized mysqli connection
|
||||||
│ ├── ErrorHandler.php # Global error/exception handler
|
│ ├── ErrorHandler.php # Global error/exception handler
|
||||||
│ ├── NotificationHelper.php # Matrix hookshot webhook events
|
│ ├── NotificationHelper.php # Matrix hookshot webhook events
|
||||||
│ ├── OutputHelper.php # Safe HTML output helpers
|
|
||||||
│ ├── ResponseHelper.php # JSON API response helpers
|
│ ├── ResponseHelper.php # JSON API response helpers
|
||||||
│ ├── SynapseHelper.php # Resolves usernames → Matrix IDs via Synapse admin API
|
│ ├── SynapseHelper.php # Resolves usernames → Matrix IDs via Synapse admin API
|
||||||
│ └── UrlHelper.php # Canonical ticket URLs using APP_DOMAIN
|
│ └── UrlHelper.php # Canonical ticket URLs using APP_DOMAIN
|
||||||
|
|||||||
@@ -1,212 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OutputHelper - Consistent output escaping utilities
|
|
||||||
*
|
|
||||||
* Provides secure HTML escaping functions to prevent XSS attacks.
|
|
||||||
* Use these functions when outputting user-controlled data.
|
|
||||||
*/
|
|
||||||
class OutputHelper
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Escape string for HTML output
|
|
||||||
*
|
|
||||||
* Use for text content inside HTML elements.
|
|
||||||
* Example: <p><?= OutputHelper::h($userInput) ?></p>
|
|
||||||
*
|
|
||||||
* @param string|null $string The string to escape
|
|
||||||
* @param int $flags htmlspecialchars flags (default: ENT_QUOTES | ENT_HTML5)
|
|
||||||
* @return string Escaped string
|
|
||||||
*/
|
|
||||||
public static function h(?string $string, int $flags = ENT_QUOTES | ENT_HTML5): string
|
|
||||||
{
|
|
||||||
if ($string === null) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return htmlspecialchars($string, $flags, 'UTF-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Escape string for HTML attribute context
|
|
||||||
*
|
|
||||||
* Use for values inside HTML attributes.
|
|
||||||
* Example: <input value="<?= OutputHelper::attr($userInput) ?>">
|
|
||||||
*
|
|
||||||
* @param string|null $string The string to escape
|
|
||||||
* @return string Escaped string
|
|
||||||
*/
|
|
||||||
public static function attr(?string $string): string
|
|
||||||
{
|
|
||||||
if ($string === null) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
// More aggressive escaping for attribute context
|
|
||||||
return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE, 'UTF-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode data as JSON for JavaScript context
|
|
||||||
*
|
|
||||||
* Use when embedding data in JavaScript.
|
|
||||||
* Example: <script>const data = <?= OutputHelper::json($data) ?>;</script>
|
|
||||||
*
|
|
||||||
* @param mixed $data The data to encode
|
|
||||||
* @param int $flags json_encode flags
|
|
||||||
* @return string JSON encoded string (safe for script context)
|
|
||||||
*/
|
|
||||||
public static function json($data, int $flags = 0): string
|
|
||||||
{
|
|
||||||
// Use HEX encoding for safety in HTML context
|
|
||||||
$safeFlags = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | $flags;
|
|
||||||
return json_encode($data, $safeFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL encode a string
|
|
||||||
*
|
|
||||||
* Use for values in URL query strings.
|
|
||||||
* Example: <a href="/search?q=<?= OutputHelper::url($query) ?>">
|
|
||||||
*
|
|
||||||
* @param string|null $string The string to encode
|
|
||||||
* @return string URL encoded string
|
|
||||||
*/
|
|
||||||
public static function url(?string $string): string
|
|
||||||
{
|
|
||||||
if ($string === null) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return rawurlencode($string);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Escape for CSS context
|
|
||||||
*
|
|
||||||
* Use for values in inline CSS.
|
|
||||||
* Example: <div style="color: <?= OutputHelper::css($color) ?>;">
|
|
||||||
*
|
|
||||||
* @param string|null $string The string to escape
|
|
||||||
* @return string Escaped string (only allows safe characters)
|
|
||||||
*/
|
|
||||||
public static function css(?string $string): string
|
|
||||||
{
|
|
||||||
if ($string === null) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
// Only allow alphanumeric, hyphens, underscores, spaces, and common CSS values
|
|
||||||
if (!preg_match('/^[a-zA-Z0-9_\-\s#.,()%]+$/', $string)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a number safely
|
|
||||||
*
|
|
||||||
* Ensures output is always a valid number.
|
|
||||||
*
|
|
||||||
* @param mixed $number The number to format
|
|
||||||
* @param int $decimals Number of decimal places
|
|
||||||
* @return string Formatted number
|
|
||||||
*/
|
|
||||||
public static function number($number, int $decimals = 0): string
|
|
||||||
{
|
|
||||||
return number_format((float)$number, $decimals, '.', ',');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format an integer safely
|
|
||||||
*
|
|
||||||
* @param mixed $value The value to format
|
|
||||||
* @return int Integer value
|
|
||||||
*/
|
|
||||||
public static function int($value): int
|
|
||||||
{
|
|
||||||
return (int)$value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Truncate string with ellipsis
|
|
||||||
*
|
|
||||||
* @param string|null $string The string to truncate
|
|
||||||
* @param int $length Maximum length
|
|
||||||
* @param string $suffix Suffix to add if truncated
|
|
||||||
* @return string Truncated and escaped string
|
|
||||||
*/
|
|
||||||
public static function truncate(?string $string, int $length = 100, string $suffix = '...'): string
|
|
||||||
{
|
|
||||||
if ($string === null) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mb_strlen($string, 'UTF-8') <= $length) {
|
|
||||||
return self::h($string);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::h(mb_substr($string, 0, $length, 'UTF-8')) . self::h($suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a date safely
|
|
||||||
*
|
|
||||||
* @param string|int|null $date Date string, timestamp, or null
|
|
||||||
* @param string $format PHP date format
|
|
||||||
* @return string Formatted date
|
|
||||||
*/
|
|
||||||
public static function date($date, string $format = 'Y-m-d H:i:s'): string
|
|
||||||
{
|
|
||||||
if ($date === null || $date === '') {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_numeric($date)) {
|
|
||||||
return date($format, (int)$date);
|
|
||||||
}
|
|
||||||
|
|
||||||
$timestamp = strtotime($date);
|
|
||||||
if ($timestamp === false) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return date($format, $timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a string is safe for use as a CSS class name
|
|
||||||
*
|
|
||||||
* @param string $class The class name to validate
|
|
||||||
* @return bool True if safe
|
|
||||||
*/
|
|
||||||
public static function isValidCssClass(string $class): bool
|
|
||||||
{
|
|
||||||
return preg_match('/^[a-zA-Z_][a-zA-Z0-9_-]*$/', $class) === 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sanitize CSS class name(s)
|
|
||||||
*
|
|
||||||
* @param string|null $classes Space-separated class names
|
|
||||||
* @return string Sanitized class names
|
|
||||||
*/
|
|
||||||
public static function cssClass(?string $classes): string
|
|
||||||
{
|
|
||||||
if ($classes === null || $classes === '') {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$classList = explode(' ', $classes);
|
|
||||||
$validClasses = array_filter($classList, [self::class, 'isValidCssClass']);
|
|
||||||
|
|
||||||
return implode(' ', $validClasses);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shorthand function for HTML escaping
|
|
||||||
*
|
|
||||||
* @param string|null $string The string to escape
|
|
||||||
* @return string Escaped string
|
|
||||||
*/
|
|
||||||
function h(?string $string): string
|
|
||||||
{
|
|
||||||
return OutputHelper::h($string);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user