<?php
/**
* @class html
* @brief HTML utilities
*
* @package Clearbricks
* @subpackage Common
*
* @copyright Olivier Meunier & Association Dotclear
* @copyright GPL-2.0-only
*/
class html
{
public static $url_root;
public static $absolute_regs = []; ///< Array of regular expression for {@link absoluteURLs()}
/**
* HTML escape
*
* Replaces HTML special characters by entities.
*
* @param string $str String to escape
* @return string
*/
public static function escapeHTML(?string $str): string
{
return htmlspecialchars($str ?? '', ENT_COMPAT, 'UTF-8');
}
/**
* Decode HTML entities
*
* Returns a string with all entities decoded.
*
* @param string $str String to protect
* @param string|bool $keep_special Keep special characters: > < &
* @return string
*/
public static function decodeEntities(?string $str, $keep_special = false): string
{
if ($keep_special) {
$str = str_replace(
['&', '>', '<'],
['&amp;', '&gt;', '&lt;'],
$str
);
}
# Some extra replacements
$extra = [
''' => "'",
];
$str = str_replace(array_keys($extra), array_values($extra), $str);
return html_entity_decode($str, ENT_QUOTES, 'UTF-8');
}
/**
* Remove markup
*
* Removes every tags, comments, cdata from string
*
* @param string $str String to clean
* @return string
*/
public static function clean(?string $str): string
{
$str = strip_tags($str);
return $str;
}
/**
* Javascript escape
*
* Returns a protected JavaScript string
*
* @param string $str String to protect
* @return string
*/
public static function escapeJS(?string $str): string
{
$str = htmlspecialchars($str, ENT_NOQUOTES, 'UTF-8');
$str = str_replace("'", "\'", $str);
$str = str_replace('"', '\"', $str);
return $str;
}
/**
* URL escape
*
* Returns an escaped URL string for HTML content
*
* @param string $str String to escape
* @return string
*/
public static function escapeURL(?string $str): string
{
return str_replace('&', '&', $str);
}
/**
* URL sanitize
*
* Encode every parts between / in url
*
* @param string $str String to satinyze
* @return string
*/
public static function sanitizeURL(?string $str): string
{
return str_replace('%2F', '/', rawurlencode($str));
}
/**
* Remove host in URL
*
* Removes host part in URL
*
* @param string $url URL to transform
* @return string
*/
public static function stripHostURL(?string $url): string
{
return preg_replace('|^[a-z]{3,}://.*?(/.*$)|', '$1', $url);
}
/**
* Set links to absolute ones
*
* Appends $root URL to URIs attributes in $str.
*
* @param string $str HTML to transform
* @param string $root Base URL
* @return string
*/
public static function absoluteURLs(?string $str, ?string $root): string
{
self::$url_root = $root;
$attr = 'action|background|cite|classid|code|codebase|data|download|formaction|href|longdesc|profile|src|usemap';
$str = preg_replace_callback('/((?:' . $attr . ')=")(.*?)(")/msu', ['self', 'absoluteURLHandler'], $str);
foreach (self::$absolute_regs as $r) {
$str = preg_replace_callback($r, ['self', 'absoluteURLHandler'], $str);
}
self::$url_root = null;
return $str;
}
private static function absoluteURLHandler(array $m): string
{
$url = $m[2];
$link = str_replace('%', '%%', $m[1]) . '%s' . str_replace('%', '%%', $m[3]);
$host = preg_replace('|^([a-z]{3,}://)(.*?)/(.*)$|', '$1$2', self::$url_root);
$parse = parse_url($m[2]);
if (empty($parse['scheme'])) {
if (strpos($url, '//') === 0) {
// Nothing to do. Already an absolute URL.
} elseif (strpos($url, '/') === 0) {
// Beginning by a / return host + url
$url = $host . $url;
} elseif (strpos($url, '#') === 0) {
// Beginning by a # return root + hash
$url = self::$url_root . $url;
} elseif (preg_match('|/$|', self::$url_root)) {
// Root is ending by / return root + url
$url = self::$url_root . $url;
} else {
$url = dirname(self::$url_root) . '/' . $url;
}
}
return sprintf($link, $url);
}
}