PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/classphp/flourish/fHTML.php

https://github.com/jsuarez/Lexer
PHP | 309 lines | 134 code | 46 blank | 129 comment | 23 complexity | 57e670d6c23144bc684f1109cc1c08b7 MD5 | raw file
  1. <?php
  2. /**
  3. * Provides HTML-related methods
  4. *
  5. * This class is implemented to use the UTF-8 character encoding. Please see
  6. * http://flourishlib.com/docs/UTF-8 for more information.
  7. *
  8. * @copyright Copyright (c) 2007-2009 Will Bond
  9. * @author Will Bond [wb] <will@flourishlib.com>
  10. * @license http://flourishlib.com/license
  11. *
  12. * @package Flourish
  13. * @link http://flourishlib.com/fHTML
  14. *
  15. * @version 1.0.0b6
  16. * #changes 1.0.0b6 Updated ::showChecked() to require strict equality if one parameter is `NULL` [wb, 2009-06-02]
  17. * @changes 1.0.0b5 Fixed ::prepare() so it does not encode multi-line HTML comments [wb, 2009-05-09]
  18. * @changes 1.0.0b4 Added methods ::printOption() and ::showChecked() that were in fCRUD [wb, 2009-05-08]
  19. * @changes 1.0.0b3 Fixed a bug where ::makeLinks() would double-link some URLs [wb, 2009-01-08]
  20. * @changes 1.0.0b2 Fixed a bug where ::makeLinks() would create links out of URLs in HTML tags [wb, 2008-12-05]
  21. * @changes 1.0.0b The initial implementation [wb, 2007-09-25]
  22. */
  23. class fHTML
  24. {
  25. // The following constants allow for nice looking callbacks to static methods
  26. const containsBlockLevelHTML = 'fHTML::containsBlockLevelHTML';
  27. const convertNewlines = 'fHTML::convertNewlines';
  28. const decode = 'fHTML::decode';
  29. const encode = 'fHTML::encode';
  30. const makeLinks = 'fHTML::makeLinks';
  31. const prepare = 'fHTML::prepare';
  32. const printOption = 'fHTML::printOption';
  33. const sendHeader = 'fHTML::sendHeader';
  34. const show = 'fHTML::show';
  35. const showChecked = 'fHTML::showChecked';
  36. /**
  37. * Checks a string of HTML for block level elements
  38. *
  39. * @param string $content The HTML content to check
  40. * @return boolean If the content contains a block level tag
  41. */
  42. static public function containsBlockLevelHTML($content)
  43. {
  44. static $inline_tags = '<a><abbr><acronym><b><big><br><button><cite><code><del><dfn><em><font><i><img><input><ins><kbd><label><q><s><samp><select><small><span><strike><strong><sub><sup><textarea><tt><u><var>';
  45. return strip_tags($content, $inline_tags) != $content;
  46. }
  47. /**
  48. * Converts newlines into `br` tags as long as there aren't any block-level HTML tags present
  49. *
  50. * @param string $content The content to display
  51. * @return void
  52. */
  53. static public function convertNewlines($content)
  54. {
  55. static $inline_tags_minus_br = '<a><abbr><acronym><b><big><button><cite><code><del><dfn><em><font><i><img><input><ins><kbd><label><q><s><samp><select><small><span><strike><strong><sub><sup><textarea><tt><u><var>';
  56. return (strip_tags($content, $inline_tags_minus_br) != $content) ? $content : nl2br($content);
  57. }
  58. /**
  59. * Converts all HTML entities to normal characters, using UTF-8
  60. *
  61. * @param string $content The content to decode
  62. * @return string The decoded content
  63. */
  64. static public function decode($content)
  65. {
  66. return html_entity_decode($content, ENT_QUOTES, 'UTF-8');
  67. }
  68. /**
  69. * Converts all special characters to entites, using UTF-8.
  70. *
  71. * @param string $content The content to encode
  72. * @return string The encoded content
  73. */
  74. static public function encode($content)
  75. {
  76. return htmlentities($content, ENT_QUOTES, 'UTF-8');
  77. }
  78. /**
  79. * Takes a block of text and converts all URLs into HTML links
  80. *
  81. * @param string $content The content to parse for links
  82. * @param integer $link_text_length If non-zero, all link text will be truncated to this many characters
  83. * @return string The content with all URLs converted to HTML link
  84. */
  85. static public function makeLinks($content, $link_text_length=0)
  86. {
  87. // Find all a tags with contents, individual HTML tags and HTML comments
  88. $reg_exp = "/<\s*a(?:\s+[\w:]+(?:\s*=\s*(?:\"[^\"]*?\"|'[^']*?'|[^'\">\s]+))?)*\s*>.*?<\s*\/\s*a\s*>|<\s*\/?\s*[\w:]+(?:\s+[\w:]+(?:\s*=\s*(?:\"[^\"]*?\"|'[^']*?'|[^'\">\s]+))?)*\s*\/?\s*>|<\!--.*?-->/";
  89. preg_match_all($reg_exp, $content, $html_matches, PREG_SET_ORDER);
  90. // Find all text
  91. $text_matches = preg_split($reg_exp, $content);
  92. // For each chunk of text and create the links
  93. foreach($text_matches as $key => $text) {
  94. preg_match_all(
  95. '~
  96. \b([a-z]{3,}://[a-z0-9%\$\-_.+!*;/?:@=&\'\#,]+[a-z0-9\$\-_+!*;/?:@=&\'\#,])\b | # Fully URLs
  97. \b(www\.(?:[a-z0-9\-]+\.)+[a-z]{2,}(?:/[a-z0-9%\$\-_.+!*;/?:@=&\'\#,]+[a-z0-9\$\-_+!*;/?:@=&\'\#,])?)\b | # www. domains
  98. \b([a-z0-9\\.+\'_\\-]+@(?:[a-z0-9\\-]+\.)+[a-z]{2,})\b # email addresses
  99. ~ix',
  100. $text,
  101. $matches,
  102. PREG_SET_ORDER
  103. );
  104. // For each match we find the first occurence, replace it and then
  105. // start from the end of that finding the next occurence. This
  106. // prevents double linking of matches for http://www.example.com and
  107. // www.example.com
  108. $last_pos = 0;
  109. foreach ($matches as $match) {
  110. $match_pos = strpos($text, $match[0], $last_pos);
  111. $length = strlen($match[0]);
  112. $prefix = '';
  113. if (!empty($match[3])) {
  114. $prefix = 'mailto:';
  115. } elseif (!empty($match[2])) {
  116. $prefix = 'http://';
  117. }
  118. $replacement = '<a href="' . $prefix . $match[0] . '">';
  119. $replacement .= ($link_text_length && strlen($match[0]) > $link_text_length) ? substr($match[0], 0, $link_text_length) . "…" : $match[0];
  120. $replacement .= '</a>';
  121. $text = substr_replace(
  122. $text,
  123. $replacement,
  124. $match_pos,
  125. $length
  126. );
  127. $last_pos = $match_pos + strlen($replacement);
  128. }
  129. $text_matches[$key] = $text;
  130. }
  131. // Merge the text and html back together
  132. for ($i = 0; $i < sizeof($html_matches); $i++) {
  133. $text_matches[$i] .= $html_matches[$i][0];
  134. }
  135. return implode($text_matches);
  136. }
  137. /**
  138. * Prepares content for display in UTF-8 encoded HTML - allows HTML tags
  139. *
  140. * @param string $content The content to prepare
  141. * @return string The encoded html
  142. */
  143. static public function prepare($content)
  144. {
  145. // Find all html tags, entities and comments
  146. $reg_exp = "/<\s*\/?\s*[\w:]+(?:\s+[\w:]+(?:\s*=\s*(?:\"[^\"]*?\"|'[^']*?'|[^'\">\s]+))?)*\s*\/?\s*>|&(?:#\d+|\w+);|<\!--(.|\n)*?-->/";
  147. preg_match_all($reg_exp, $content, $html_matches, PREG_SET_ORDER);
  148. // Find all text
  149. $text_matches = preg_split($reg_exp, $content);
  150. // For each chunk of text, make sure it is converted to entities
  151. foreach($text_matches as $key => $value) {
  152. $text_matches[$key] = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
  153. }
  154. // Merge the text and html back together
  155. for ($i = 0; $i < sizeof($html_matches); $i++) {
  156. $text_matches[$i] .= $html_matches[$i][0];
  157. }
  158. return implode($text_matches);
  159. }
  160. /**
  161. * Prints an `option` tag with the provided value, using the selected value to determine if the option should be marked as selected
  162. *
  163. * @param string $text The text to display in the option tag
  164. * @param string $value The value for the option
  165. * @param string $selected_value If the value is the same as this, the option will be marked as selected
  166. * @return void
  167. */
  168. static public function printOption($text, $value, $selected_value=NULL)
  169. {
  170. $selected = FALSE;
  171. if ($value == $selected_value || (is_array($selected_value) && in_array($value, $selected_value))) {
  172. $selected = TRUE;
  173. }
  174. echo '<option value="' . fHTML::encode($value) . '"';
  175. if ($selected) {
  176. echo ' selected="selected"';
  177. }
  178. echo '>' . fHTML::prepare($text) . '</option>';
  179. }
  180. /**
  181. * Sets the proper Content-Type header for a UTF-8 HTML (or pseudo-XHTML) page
  182. *
  183. * @return void
  184. */
  185. static public function sendHeader()
  186. {
  187. header('Content-Type: text/html; charset=utf-8');
  188. }
  189. /**
  190. * Prints a `p` (or `div` if the content has block-level HTML) tag with the contents and the class specified - will not print if no content
  191. *
  192. * @param string $content The content to display
  193. * @param string $css_class The CSS class to apply
  194. * @return boolean If the content was shown
  195. */
  196. static public function show($content, $css_class='')
  197. {
  198. if ((!is_string($content) && !is_object($content) && !is_numeric($content)) || !strlen(trim($content))) {
  199. return FALSE;
  200. }
  201. $class = ($css_class) ? ' class="' . $css_class . '"' : '';
  202. if (self::containsBlockLevelHTML($content)) {
  203. echo '<div' . $class . '>' . self::prepare($content) . '</div>';
  204. } else {
  205. echo '<p' . $class . '>' . self::prepare($content) . '</p>';
  206. }
  207. return TRUE;
  208. }
  209. /**
  210. * Prints a `checked="checked"` HTML input attribute if `$value` equals `$checked_value`, or if `$value` is in `$checked_value`
  211. *
  212. * Please note that if either `$value` or `$checked_value` is `NULL`, a
  213. * strict comparison will be performed, whereas normally a non-strict
  214. * comparison is made. Thus `0` and `FALSE` will cause the checked
  215. * attribute to be printed, but `0` and `NULL` will not.
  216. *
  217. * @param string $value The value for the current HTML input tag
  218. * @param string|array $checked_value The value (or array of values) that has been checked
  219. * @return boolean If the checked attribute was printed
  220. */
  221. static public function showChecked($value, $checked_value)
  222. {
  223. $checked = FALSE;
  224. $one_null = $value === NULL || $checked_value === NULL;
  225. $equal = ($one_null) ? $value === $checked_value : $value == $checked_value;
  226. $in_array = is_array($checked_value) && in_array($value, $checked_value, $one_null ? TRUE : FALSE);
  227. if ($equal || $in_array) {
  228. $checked = TRUE;
  229. }
  230. if ($checked) {
  231. echo ' checked="checked"';
  232. return TRUE;
  233. }
  234. return FALSE;
  235. }
  236. /**
  237. * Forces use as a static class
  238. *
  239. * @return fHTML
  240. */
  241. private function __construct() { }
  242. }
  243. /**
  244. * Copyright (c) 2007-2009 Will Bond <will@flourishlib.com>
  245. *
  246. * Permission is hereby granted, free of charge, to any person obtaining a copy
  247. * of this software and associated documentation files (the "Software"), to deal
  248. * in the Software without restriction, including without limitation the rights
  249. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  250. * copies of the Software, and to permit persons to whom the Software is
  251. * furnished to do so, subject to the following conditions:
  252. *
  253. * The above copyright notice and this permission notice shall be included in
  254. * all copies or substantial portions of the Software.
  255. *
  256. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  257. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  258. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  259. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  260. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  261. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  262. * THE SOFTWARE.
  263. */