HTML.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. <?php
  2. /**
  3. * HTML helper class. Provides generic methods for generating various HTML
  4. * tags and making output HTML safe.
  5. *
  6. * @package KO7
  7. * @category Helpers
  8. *
  9. * @copyright (c) 2007-2016 Kohana Team
  10. * @copyright (c) since 2016 Koseven Team
  11. * @license https://koseven.dev/LICENSE
  12. */
  13. class KO7_HTML {
  14. /**
  15. * @var array preferred order of attributes
  16. */
  17. public static $attribute_order = [
  18. 'action',
  19. 'method',
  20. 'type',
  21. 'id',
  22. 'name',
  23. 'value',
  24. 'href',
  25. 'src',
  26. 'width',
  27. 'height',
  28. 'cols',
  29. 'rows',
  30. 'size',
  31. 'maxlength',
  32. 'rel',
  33. 'media',
  34. 'accept-charset',
  35. 'accept',
  36. 'tabindex',
  37. 'accesskey',
  38. 'alt',
  39. 'title',
  40. 'class',
  41. 'style',
  42. 'selected',
  43. 'checked',
  44. 'readonly',
  45. 'disabled',
  46. ];
  47. /**
  48. * @var boolean use strict XHTML mode?
  49. */
  50. public static $strict = TRUE;
  51. /**
  52. * @var boolean automatically target external URLs to a new window?
  53. */
  54. public static $windowed_urls = FALSE;
  55. /**
  56. * Convert special characters to HTML entities. All untrusted content
  57. * should be passed through this method to prevent XSS injections.
  58. *
  59. * echo HTML::chars($username);
  60. *
  61. * @param string $value string to convert
  62. * @param boolean $double_encode encode existing entities
  63. * @return string
  64. */
  65. public static function chars($value, $double_encode = TRUE)
  66. {
  67. return htmlspecialchars( (string) $value, ENT_QUOTES, KO7::$charset, $double_encode);
  68. }
  69. /**
  70. * Convert all applicable characters to HTML entities. All characters
  71. * that cannot be represented in HTML with the current character set
  72. * will be converted to entities.
  73. *
  74. * echo HTML::entities($username);
  75. *
  76. * @param string $value string to convert
  77. * @param boolean $double_encode encode existing entities
  78. * @return string
  79. */
  80. public static function entities($value, $double_encode = TRUE)
  81. {
  82. return htmlentities( (string) $value, ENT_QUOTES, KO7::$charset, $double_encode);
  83. }
  84. /**
  85. * Create HTML link anchors. Note that the title is not escaped, to allow
  86. * HTML elements within links (images, etc).
  87. *
  88. * echo HTML::anchor('/user/profile', 'My Profile');
  89. *
  90. * @param string $uri URL or URI string
  91. * @param string $title link text
  92. * @param array $attributes HTML anchor attributes
  93. * @param mixed $protocol protocol to pass to URL::base()
  94. * @param boolean $index include the index page
  95. * @return string
  96. * @uses URL::base
  97. * @uses URL::site
  98. * @uses HTML::attributes
  99. */
  100. public static function anchor($uri, $title = NULL, array $attributes = NULL, $protocol = NULL, $index = TRUE)
  101. {
  102. if ($title === NULL)
  103. {
  104. // Use the URI as the title
  105. $title = $uri;
  106. }
  107. if ($uri === '')
  108. {
  109. // Only use the base URL
  110. $uri = URL::base($protocol, $index);
  111. }
  112. else
  113. {
  114. if (strpos($uri, '://') !== FALSE OR strncmp($uri, '//', 2) == 0)
  115. {
  116. if (HTML::$windowed_urls === TRUE AND empty($attributes['target']))
  117. {
  118. // Make the link open in a new window
  119. $attributes['target'] = '_blank';
  120. }
  121. }
  122. elseif ($uri[0] !== '#' AND $uri[0] !== '?')
  123. {
  124. // Make the URI absolute for non-fragment and non-query anchors
  125. $uri = URL::site($uri, $protocol, $index);
  126. }
  127. }
  128. // Add the sanitized link to the attributes
  129. $attributes['href'] = $uri;
  130. return '<a'.HTML::attributes($attributes).'>'.$title.'</a>';
  131. }
  132. /**
  133. * Creates an HTML anchor to a file. Note that the title is not escaped,
  134. * to allow HTML elements within links (images, etc).
  135. *
  136. * echo HTML::file_anchor('media/doc/user_guide.pdf', 'User Guide');
  137. *
  138. * @param string $file name of file to link to
  139. * @param string $title link text
  140. * @param array $attributes HTML anchor attributes
  141. * @param mixed $protocol protocol to pass to URL::base()
  142. * @param boolean $index include the index page
  143. * @return string
  144. * @uses URL::base
  145. * @uses HTML::attributes
  146. */
  147. public static function file_anchor($file, $title = NULL, array $attributes = NULL, $protocol = NULL, $index = FALSE)
  148. {
  149. if ($title === NULL)
  150. {
  151. // Use the file name as the title
  152. $title = basename($file);
  153. }
  154. // Add the file link to the attributes
  155. $attributes['href'] = URL::site($file, $protocol, $index);
  156. return '<a'.HTML::attributes($attributes).'>'.$title.'</a>';
  157. }
  158. /**
  159. * Creates an email (mailto:) anchor. Note that the title is not escaped,
  160. * to allow HTML elements within links (images, etc).
  161. *
  162. * echo HTML::mailto($address);
  163. *
  164. * @param string $email email address to send to
  165. * @param string $title link text
  166. * @param array $attributes HTML anchor attributes
  167. * @return string
  168. * @uses HTML::attributes
  169. */
  170. public static function mailto($email, $title = NULL, array $attributes = NULL)
  171. {
  172. if ($title === NULL)
  173. {
  174. // Use the email address as the title
  175. $title = $email;
  176. }
  177. return '<a href="&#109;&#097;&#105;&#108;&#116;&#111;&#058;'.$email.'"'.HTML::attributes($attributes).'>'.$title.'</a>';
  178. }
  179. /**
  180. * Creates a style sheet link element.
  181. *
  182. * echo HTML::style('media/css/screen.css');
  183. *
  184. * @param string $file file name
  185. * @param array $attributes default attributes
  186. * @param mixed $protocol protocol to pass to URL::base()
  187. * @param boolean $index include the index page
  188. * @return string
  189. * @uses URL::base
  190. * @uses HTML::attributes
  191. */
  192. public static function style($file, array $attributes = NULL, $protocol = NULL, $index = FALSE)
  193. {
  194. if (strpos($file, '://') === FALSE AND strncmp($file, '//', 2))
  195. {
  196. // Add the base URL
  197. $file = URL::site($file, $protocol, $index);
  198. }
  199. // Set the stylesheet link
  200. $attributes['href'] = $file;
  201. // Set the stylesheet rel
  202. $attributes['rel'] = empty($attributes['rel']) ? 'stylesheet' : $attributes['rel'];
  203. // Set the stylesheet type
  204. $attributes['type'] = 'text/css';
  205. return '<link'.HTML::attributes($attributes).' />';
  206. }
  207. /**
  208. * Creates a script link.
  209. *
  210. * echo HTML::script('media/js/jquery.min.js');
  211. *
  212. * @param string $file file name
  213. * @param array $attributes default attributes
  214. * @param mixed $protocol protocol to pass to URL::base()
  215. * @param boolean $index include the index page
  216. * @return string
  217. * @uses URL::base
  218. * @uses HTML::attributes
  219. */
  220. public static function script($file, array $attributes = NULL, $protocol = NULL, $index = FALSE)
  221. {
  222. if (strpos($file, '://') === FALSE AND strncmp($file, '//', 2))
  223. {
  224. // Add the base URL
  225. $file = URL::site($file, $protocol, $index);
  226. }
  227. // Set the script link
  228. $attributes['src'] = $file;
  229. // Set the script type
  230. $attributes['type'] = 'text/javascript';
  231. return '<script'.HTML::attributes($attributes).'></script>';
  232. }
  233. /**
  234. * Creates a image link.
  235. *
  236. * echo HTML::image('media/img/logo.png', array('alt' => 'My Company'));
  237. *
  238. * @param string $file file name
  239. * @param array $attributes default attributes
  240. * @param mixed $protocol protocol to pass to URL::base()
  241. * @param boolean $index include the index page
  242. * @return string
  243. * @uses URL::base
  244. * @uses HTML::attributes
  245. */
  246. public static function image($file, array $attributes = NULL, $protocol = NULL, $index = FALSE)
  247. {
  248. if (strpos($file, '://') === FALSE AND strncmp($file, '//', 2) AND strncmp($file, 'data:', 5))
  249. {
  250. // Add the base URL
  251. $file = URL::site($file, $protocol, $index);
  252. }
  253. // Add the image link
  254. $attributes['src'] = $file;
  255. return '<img'.HTML::attributes($attributes).' />';
  256. }
  257. /**
  258. * Compiles an array of HTML attributes into an attribute string.
  259. * Attributes will be sorted using HTML::$attribute_order for consistency.
  260. *
  261. * echo '<div'.HTML::attributes($attrs).'>'.$content.'</div>';
  262. *
  263. * @param array $attributes attribute list
  264. * @return string
  265. */
  266. public static function attributes(array $attributes = NULL)
  267. {
  268. if (empty($attributes))
  269. return '';
  270. $sorted = [];
  271. foreach (HTML::$attribute_order as $key)
  272. {
  273. if (isset($attributes[$key]))
  274. {
  275. // Add the attribute to the sorted list
  276. $sorted[$key] = $attributes[$key];
  277. }
  278. }
  279. // Combine the sorted attributes
  280. $attributes = $sorted + $attributes;
  281. $compiled = '';
  282. foreach ($attributes as $key => $value)
  283. {
  284. if ($value === NULL)
  285. {
  286. // Skip attributes that have NULL values
  287. continue;
  288. }
  289. if (is_int($key))
  290. {
  291. // Assume non-associative keys are mirrored attributes
  292. $key = $value;
  293. if ( ! HTML::$strict)
  294. {
  295. // Just use a key
  296. $value = FALSE;
  297. }
  298. }
  299. // Add the attribute key
  300. $compiled .= ' '.$key;
  301. if ($value OR HTML::$strict)
  302. {
  303. // Add the attribute value
  304. $compiled .= '="'.HTML::chars($value).'"';
  305. }
  306. }
  307. return $compiled;
  308. }
  309. /**
  310. * Creates an HTML tag element.
  311. *
  312. * echo HTML::tag('div', 'Hello world');
  313. *
  314. * @param string $type HTML element
  315. * @param string $content content of the HTML element
  316. * @param array $attributes default attributes
  317. * @return string
  318. * @uses HTML::attributes
  319. */
  320. public static function tag($type, $content = NULL, array $attributes = NULL): string
  321. {
  322. if ( ! is_array($attributes))
  323. $attributes = [];
  324. return '<'.$type.' '.self::attributes($attributes).'>'.$content.'</'.$type.'>';
  325. }
  326. }