/** * prepare a multi-part message * * @param string message HTML tags or ASCII content * @return array containing message parts ($type => $content) */ public static function build_multipart($text) { global $context; // make a full html entity --body attributes are ignored most of the time $text = '<html><body>' . MAIL_FONT_PREFIX . $text . MAIL_FONT_SUFFIX . '</body></html>'; // change links to include host name $text = str_replace(' href="/', ' href="' . $context['url_to_home'] . '/', $text); $text = str_replace(' src="/', ' src="' . $context['url_to_home'] . '/', $text); // remove invisible tags, such as scripts, etc. $text = xml::strip_invisible_tags($text); // one element per type $message = array(); // text/plain part has no tag anymore $replacements = array('#<a [^>]*?><img [^>]*?></a>#i' => '', "#<a href=\"([^\"]+?)\"([^>]*?)>\$1</a>#i" => "\$1", '#<a href="([^"]+?)" ([^>]*?)>(.*?)</a>#i' => "\$3 \$1", '/<a href=\\"([^\\"]+?)">(.*?)<\\/a>/i' => "\$2 \$1", '/<hr[^>]*?>/i' => "-------\n", '/ /' => ' '); // text/plain part $message['text/plain; charset=utf-8'] = utf8::from_unicode(utf8::encode(trim(html_entity_decode(xml::strip_visible_tags(preg_replace(array_keys($replacements), array_values($replacements), $text), ''), ENT_QUOTES, 'UTF-8')))); // transform the text/html part $replacements = array('#<dl[^>]*?>(.*?)</dl>#siu' => '<table>$1</table>', '#<dt[^>]*?>(.*?)</dt>#siu' => '<tr><td>' . MAIL_FONT_PREFIX . '$1' . MAIL_FONT_SUFFIX . '</td>', '#<dd[^>]*?>(.*?)</dd>#siu' => '<td>' . MAIL_FONT_PREFIX . '$1' . MAIL_FONT_SUFFIX . '</td></tr>', '#class="grid"#i' => 'border="1" cellspacing="0" cellpadding="10"', '#on(click|keypress)="([^"]+?)"#i' => '', '#/>#i' => '>'); // text/html part $message['text/html; charset=utf-8'] = preg_replace(array_keys($replacements), array_values($replacements), $text); // return all parts return $message; }
/** * get some introductory text from a section * * This function is used to introduce comments, or any sub-item related to an anchor. * Compared to the standard anchor implementation, this one adds the ability to handle overlay data. * * If there is some introductory text, it is used. Else the description text is used instead. * The number of words is capped in both cases. * * Also, the number of remaining words is provided. * * Following variants may be selected to adapt to various situations: * - 'basic' - strip every tag, we want almost plain ASCII - maybe this will be send in a mail message * - 'hover' - some text to be displayed while hovering a link * - 'quote' - transform YACS codes, then strip most HTML tags * - 'teaser' - limit the number of words, tranform YACS codes, and link to permalink * * @see shared/anchor.php * * @param string an optional variant * @return NULL, of some text */ function &get_teaser($variant = 'basic') { global $context; // nothing to do if (!isset($this->item['id'])) { $text = NULL; return $text; } // the text to be returned $text = ''; // use the introduction field, if any if ($this->item['introduction']) { $text = trim($this->item['introduction']); // may be rendered as an empty strings if ($variant != 'hover') { // remove toc and toq codes $text = preg_replace(FORBIDDEN_IN_TEASERS, '', $text); // render all codes if (is_callable(array('Codes', 'beautify'))) { $text =& Codes::beautify($text, $this->item['options']); } } // remove most html if ($variant != 'teaser') { $text = xml::strip_visible_tags($text); } // combine with description if ($variant == 'quote') { $text .= BR . BR; } } // use overlay data, if any if (!$text) { $overlay = Overlay::load($this->item, 'section:' . $this->item['id']); if (is_object($overlay)) { $text .= $overlay->get_text('list', $this->item); } } // use the description field, if any $in_description = FALSE; if (!$text && $variant != 'hover' || $variant == 'quote') { $text .= trim($this->item['description']); $in_description = TRUE; // remove toc and toq codes $text = preg_replace(FORBIDDEN_IN_TEASERS, '', $text); // render all codes if (is_callable(array('Codes', 'beautify'))) { $text =& Codes::beautify($text, $this->item['options']); } // remove most html $text = xml::strip_visible_tags($text); } // turn html entities to unicode entities $text =& utf8::transcode($text); // now we have to process the provided text switch ($variant) { // strip everything case 'basic': default: // remove most html $text = xml::strip_visible_tags($text); // limit the number of words $text =& Skin::cap($text, 70); // done return $text; // some text for pop-up panels // some text for pop-up panels case 'hover': // remove most html $text = xml::strip_visible_tags($text); // limit the number of words $text =& Skin::strip($text, 70); // ensure we have some text if (!$text) { $text = i18n::s('View the page'); } // mention shortcut to section if (Surfer::is_associate()) { $text .= ' [section=' . $this->item['id'] . ']'; } // done return $text; // quote this // quote this case 'quote': // remove most html $text = xml::strip_visible_tags($text); // limit the number of words $text =& Skin::cap($text, 300); // done return $text; // preserve as much as possible // preserve as much as possible case 'teaser': // limit the number of words $text =& Skin::cap($text, 12, $this->get_url()); // done return $text; } }
/** * strip some text, by suppressing codes, html and limiting words * * To limit the size of a string and preserve HTML tagging, you should rather consider [code]cap()[/code]. * * A stripped string is a short set of words aiming to introduce a longer page. It is * usually followed by a link to jump to the full text. * * Alternatively, this function may also be used to limit the number of words * for a plain text string. * * In both cases the calling script should be able to use the resulting directly, without any additional processing. * * Most HTML tags are suppressed by [code]Skin::strip()[/code], except <a>, <br>, <img> and <span>. * You can provide the full list of allowed tags. * * This function will strip YACS codes as well, except if you explicitly ask for codes to be processed. * * * Example: * [snippet] * Skin::strip('This is my very interesting page', 3); * [/snippet] * * will return: * [snippet] * 'This is my...' * [/snippet] * * @param string the text to abbreviate * @param int the maximum number of words in the output * @param an optional url to go to the full version, if any * @param the list of allowed HTML tags, if any * @param boolean set to TRUE if YACS codes should be rendered, else codes will be removed * @return the HTML to display */ public static function &strip($text, $count = 20, $url = NULL, $allowed_html = '<a><br><img><span>', $render_codes = FALSE) { global $context; // no follow-up yet $with_more = FALSE; // process YACS codes if ($render_codes) { // suppress dynamic tables, they would probably take too much space if (preg_match('/\\[table=(.+?)\\]/s', $text)) { $text = preg_replace(array('/\\[table=(.+?)\\]/s'), ' (table) ', $text); // append a link to the full page $with_more = TRUE; } // render all codes $text = Codes::beautify($text); } // remove invisible tags, such as scripts, etc. $text = xml::strip_invisible_tags($text); // strip most visible tags $text = trim(xml::strip_visible_tags($text, $allowed_html)); // count overall words $overall = count(preg_split("/[ \t,\\.;\\?!]+/", $text, -1, PREG_SPLIT_NO_EMPTY)); // no parsing overhead in case of short labels if ($overall <= $count) { return $text; } // skip html tags $areas = preg_split('/(<\\/{0,1}[\\w]+[^>]*>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE); $text = ''; $index = 0; $overall = 0; foreach ($areas as $area) { // tag to be preserved if ($index % 2) { $text .= $area; // check boundary after last HTML tag -- else <a>text</a> could loose closing tag if ($count < 0) { break; } // regular text } else { // count words from this area $words = preg_split("/([ \t,\\.;\\?!]+)/", $area, -1, PREG_SPLIT_DELIM_CAPTURE); // we still have some room if (count($words) <= 2 * $count) { $text .= $area; } elseif ($count > 0) { $overall += intval(count($words) / 2 - $count); // drop the tail array_splice($words, 2 * $count); // reassemble displayed words $text .= implode('', $words) . '...'; // append a link to the full page $with_more = TRUE; } else { $overall += intval(count($words) / 2); } // less words to accept $count -= intval(count($words) / 2); } $index++; } // there is more to read if ($with_more && $url) { // indicate the number of words to read, if significant text to read if ($overall > 30) { $text .= ' (' . sprintf(i18n::s('%d words to read'), $overall) . ') '; } // add a link $text .= ' ' . Skin::build_link($url, MORE_IMG, 'more', i18n::s('View the page')) . ' '; } return $text; }
/** * make a string out of something * * @param mixed something to be printed * @param boolean TRUE if HTML tags should be suppressed, FALSE otherwise * @return string */ public static function &to_string($value = '', $strip_tags = TRUE) { global $context; // a boolean if ($value === TRUE) { $value = 'TRUE'; } elseif ($value === FALSE) { $value = 'FALSE'; } elseif (isset($value) && !is_string($value)) { $value = print_r($value, TRUE); } // stick to simple line returns $value = str_replace("\r", '', $value); // log simple messages if ($strip_tags) { $value = trim(xml::strip_visible_tags(xml::strip_invisible_tags($value))); } else { $value = trim($value); } // return a clean string return $value; }