Elgg  Version 4.x
HtmlFormatter.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Views;
4 
10 
15 
16  use Loggable;
17 
21  protected $views;
22 
26  protected $hooks;
27 
31  protected $autop;
32 
40  public function __construct(
44  ) {
45  $this->views = $views;
46  $this->hooks = $hooks;
47  $this->autop = $autop;
48  }
49 
63  public function formatBlock($html, array $options = []) {
64  if (!is_string($html)) {
65  return '';
66  }
67 
68  $options = array_merge([
69  'parse_urls' => true,
70  'parse_emails' => true,
71  'sanitize' => true,
72  'autop' => true,
73  ], $options);
74 
75  $params = [
76  'options' => $options,
77  'html' => $html,
78  ];
79 
80  $params = $this->hooks->trigger('prepare', 'html', null, $params);
81 
82  $html = elgg_extract('html', $params);
83  $options = elgg_extract('options', $params);
84 
85  if (elgg_extract('parse_urls', $options)) {
86  $html = $this->parseUrls($html);
87  }
88 
89  if (elgg_extract('parse_emails', $options)) {
90  $html = $this->parseEmails($html);
91  }
92 
93  if (elgg_extract('sanitize', $options)) {
95  }
96 
97  if (elgg_extract('autop', $options)) {
98  $html = $this->addParagaraphs($html);
99  }
100 
101  return $html;
102  }
103 
111  public function parseUrls($text) {
112 
113  $linkify = new \Misd\Linkify\Linkify();
114 
115  return $linkify->processUrls($text, ['attr' => ['rel' => 'nofollow']]);
116  }
117 
127  public function parseEmails($text) {
128  $linkify = new \Misd\Linkify\Linkify();
129 
130  return $linkify->processEmails($text, ['attr' => ['rel' => 'nofollow']]);
131  }
132 
140  public function addParagaraphs($string) {
141  try {
142  $result = $this->autop->process($string);
143  if ($result !== false) {
144  return $result;
145  }
146  } catch (\RuntimeException $e) {
147  $this->getLogger()->warning('ElggAutoP failed to process the string: ' . $e->getMessage());
148  }
149 
150  return $string;
151  }
152 
177  public function formatAttributes(array $attrs = []) {
178  if (empty($attrs)) {
179  return '';
180  }
181 
182  $attributes = [];
183 
184  foreach ($attrs as $attr => $val) {
185  if (0 !== strpos($attr, 'data-') && false !== strpos($attr, '_')) {
186  // this is probably a view $vars variable not meant for output
187  continue;
188  }
189 
190  $attr = strtolower($attr);
191 
192  if (!isset($val) || $val === false) {
193  continue;
194  }
195 
196  if ($val === true) {
197  $val = $attr; //e.g. checked => true ==> checked="checked"
198  }
199 
200  if (is_array($val) && empty($val)) {
201  //e.g. ['class' => []]
202  continue;
203  }
204 
205  if (is_scalar($val)) {
206  $val = [$val];
207  }
208 
209  if (!is_array($val)) {
210  continue;
211  }
212 
213  // Check if array contains non-scalar values and bail if so
214  $filtered_val = array_filter($val, function($e) {
215  return is_scalar($e);
216  });
217 
218  if (count($val) != count($filtered_val)) {
219  continue;
220  }
221 
222  $val = implode(' ', $val);
223 
224  $val = htmlspecialchars($val, ENT_QUOTES, 'UTF-8', false);
225  $attributes[] = "$attr=\"$val\"";
226  }
227 
228  return implode(' ', $attributes);
229  }
230 
261  public function formatElement($tag_name, array $attributes = [], $text = '', array $options = []) {
262  if (is_array($tag_name)) {
263  $args = $tag_name;
264 
265  if ($attributes !== [] || $text !== '' || $options !== []) {
266  throw new InvalidArgumentException('If $tag_name is an array, the other arguments must not be set');
267  }
268 
269  if (isset($args['#tag_name'])) {
270  $tag_name = $args['#tag_name'];
271  }
272  if (isset($args['#text'])) {
273  $text = $args['#text'];
274  }
275  if (isset($args['#options'])) {
276  $options = $args['#options'];
277  }
278 
279  unset($args['#tag_name'], $args['#text'], $args['#options']);
280  $attributes = $args;
281  }
282 
283  if (!is_string($tag_name) || $tag_name === '') {
284  throw new InvalidArgumentException('$tag_name is required');
285  }
286 
287  if (isset($options['is_void'])) {
288  $is_void = $options['is_void'];
289  } else {
290  // from http://www.w3.org/TR/html-markup/syntax.html#syntax-elements
291  $is_void = in_array(strtolower($tag_name), [
292  'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem',
293  'meta', 'param', 'source', 'track', 'wbr'
294  ]);
295  }
296 
297  if (!empty($options['encode_text']) && is_string($text)) {
298  $double_encode = empty($options['double_encode']) ? false : true;
299  $text = htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', $double_encode);
300  }
301 
302  $attrs = '';
303  if (!empty($attributes)) {
305  if ($attrs !== '') {
306  $attrs = " $attrs";
307  }
308  }
309 
310  if ($is_void) {
311  return empty($options['is_xml']) ? "<{$tag_name}{$attrs}>" : "<{$tag_name}{$attrs} />";
312  }
313 
314  return "<{$tag_name}{$attrs}>$text</$tag_name>";
315  }
316 
327  public function stripTags($string, $allowable_tags = null) {
328  if (!isset($string)) {
329  return '';
330  }
331 
332  $params = [
333  'original_string' => $string,
334  'allowable_tags' => $allowable_tags,
335  ];
336 
337  $string = strip_tags($string, $allowable_tags);
338  $string = $this->hooks->trigger('format', 'strip_tags', $params, $string);
339 
340  return $string;
341  }
342 
370  public function decode($string) {
371  if (!isset($string)) {
372  return '';
373  }
374 
375  $string = str_replace(
376  ['&gt;', '&lt;', '&amp;', '&quot;', '&#039;'],
377  ['&amp;gt;', '&amp;lt;', '&amp;amp;', '&amp;quot;', '&amp;#039;'],
378  $string
379  );
380  $string = html_entity_decode($string, ENT_NOQUOTES, 'UTF-8');
381  $string = str_replace(
382  ['&amp;gt;', '&amp;lt;', '&amp;amp;', '&amp;quot;', '&amp;#039;'],
383  ['&gt;', '&lt;', '&amp;', '&quot;', '&#039;'],
384  $string
385  );
386  return $string;
387  }
388 
400  public function inlineCss(string $html, string $css, bool $body_only = false): string {
401  if (empty($html) || empty($css)) {
402  return $html;
403  }
404 
405  $inliner = CssInliner::fromHtml($html)->disableStyleBlocksParsing()->inlineCss($css);
406 
407  return $body_only ? $inliner->renderBodyContent() : $inliner->render();
408  }
409 
419  public function normalizeUrls(string $text): string {
420  $pattern = '/\s(?:href|src)=([\'"]\S+[\'"])/i';
421 
422  // find all matches
423  $matches = [];
424  preg_match_all($pattern, $text, $matches);
425 
426  if (empty($matches) || !isset($matches[1])) {
427  return $text;
428  }
429 
430  // go through all the matches
431  $urls = $matches[1];
432  $urls = array_unique($urls);
433 
434  foreach ($urls as $url) {
435  // remove wrapping quotes from the url
436  $real_url = substr($url, 1, -1);
437  // normalize url
438  $new_url = elgg_normalize_url($real_url);
439  // make the correct replacement string
440  $replacement = str_replace($real_url, $new_url, $url);
441 
442  // replace the url in the content
443  $text = str_replace($url, $replacement, $text);
444  }
445 
446  return $text;
447  }
448 }
Base exception of invalid argument exceptions in the Elgg system.
$params
Saves global plugin settings.
Definition: save.php:13
formatAttributes(array $attrs=[])
Converts an associative array into a string of well-formed HTML/XML attributes Returns a concatenated...
elgg_normalize_url($url)
Definition: output.php:152
stripTags($string, $allowable_tags=null)
Strip tags and offer plugins the chance.
normalizeUrls(string $text)
Replaces relative urls in href or src attributes in text.
$args
Some servers don&#39;t allow PHP to check the rewrite, so try via AJAX.
filter_tags($var)
Filter tags from a given string based on registered hooks.
Definition: input.php:77
formatElement($tag_name, array $attributes=[], $text= '', array $options=[])
Format an HTML element.
$options
Elgg admin footer.
Definition: footer.php:6
$html
Definition: section.php:10
decode($string)
Decode HTML markup into a raw text string.
trait Loggable
Enables adding a logger.
Definition: Loggable.php:14
__construct(ViewsService $views, PluginHooksService $hooks,\ElggAutoP $autop)
Output constructor.
parseEmails($text)
Takes a string and turns any email addresses into formatted links.
parseUrls($text)
Takes a string and turns any URLs into formatted links.
Views service.
Various helper method for formatting and sanitizing output.
$css
Definition: install.css.php:5
elgg_extract($key, $array, $default=null, $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:686
getLogger()
Returns logger.
Definition: Loggable.php:37
foreach($plugin_guids as $guid) if(empty($deactivated_plugins)) $url
Definition: deactivate.php:39
formatBlock($html, array $options=[])
Prepare HTML output.
inlineCss(string $html, string $css, bool $body_only=false)
Adds inline style to html content.
Create wrapper P and BR elements in HTML depending on newlines.
Definition: ElggAutoP.php:11
$text
Definition: button.php:32
$attributes
Elgg AJAX loader.
Definition: ajax_loader.php:10
if(empty($title)&&empty($body)) if(!empty($link)) $attrs
Definition: message.php:28
addParagaraphs($string)
Create paragraphs from text with line spacing.