| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- <?php
- App::uses('TextHelper', 'View/Helper');
- App::uses('HtmlHelper', 'View/Helper');
- App::uses('View', 'View');
- /**
- * The core text helper is unsecure and outdated in functionality
- * this aims to compensate the deficiencies
- *
- * autoLinkEmails
- * - obfuscate (defaults to FALSE right now)
- * (- maxLength?)
- * - escape (defaults to TRUE for security reasons regarding plain text)
- *
- * autoLinkUrls
- * - stripProtocol (defaults To FALSE right now)
- * - maxLength (to shorten links in order to not mess up the layout in some cases - appends ...)
- * - escape (defaults to TRUE for security reasons regarding plain text)
- *
- */
- class TextExtHelper extends TextHelper {
- /**
- * Formats paragraphs around given text for all line breaks
- * <br /> added for single line return
- * <p> added for double line return
- *
- * @param string $text Text
- * @return string The text with proper <p> and <br /> tags
- * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/text.html#TextHelper::autoParagraph
- */
- public function autoParagraph($text) {
- // for cake >= 2.4
- if (method_exists(get_parent_class(), 'autoParagraph')) {
- return parent::autoParagraph($text);
- }
- if (trim($text) !== '') {
- $text = preg_replace('|<br[^>]*>\s*<br[^>]*>|i', "\n\n", $text . "\n");
- $text = preg_replace("/\n\n+/", "\n\n", str_replace(array("\r\n", "\r"), "\n", $text));
- $texts = preg_split('/\n\s*\n/', $text, -1, PREG_SPLIT_NO_EMPTY);
- $text = '';
- foreach ($texts as $txt) {
- $text .= '<p>' . nl2br(trim($txt, "\n")) . "</p>\n";
- }
- $text = preg_replace('|<p>\s*</p>|', '', $text);
- }
- return $text;
- }
- /**
- * Convert all links and email adresses to HTML links.
- *
- * @param string $text Text
- * @param array $options Array of HTML options.
- * @return string The text with links
- * @link http://book.cakephp.org/view/1469/Text#autoLink-1620
- */
- public function autoLink($text, $options = array(), $htmlOptions = array()) {
- if (!isset($options['escape']) || $options['escape'] !== false) {
- $text = h($text);
- $options['escape'] = false;
- }
- return $this->autoLinkEmails($this->autoLinkUrls($text, $options, $htmlOptions), $options, $htmlOptions);
- }
- /**
- * Fix to allow obfuscation of email (js, img?)
- * @param string $text
- * @param htmlOptions (additionally - not yet supported by core):
- * - obfuscate: true/false (defaults to false)
- * @param array $options
- * - escape (defaults to true)
- * @return string html
- * @override
- */
- public function autoLinkEmails($text, $options = array(), $htmlOptions = array()) {
- if (!isset($options['escape']) || $options['escape'] !== false) {
- $text = h($text);
- }
- $linkOptions = 'array(';
- foreach ($htmlOptions as $option => $value) {
- $value = var_export($value, true);
- $linkOptions .= "'$option' => $value, ";
- }
- $linkOptions .= ')';
- $customOptions = 'array(';
- foreach ($options as $option => $value) {
- $value = var_export($value, true);
- $customOptions .= "'$option' => $value, ";
- }
- $customOptions .= ')';
- $atom = '[a-z0-9!#$%&\'*+\/=?^_`{|}~-]';
- return preg_replace_callback('/(' . $atom . '+(?:\.' . $atom . '+)*@[a-z0-9-]+(?:\.[a-z0-9-]+)+)/i',
- create_function('$matches', 'return TextExtHelper::prepareEmail($matches[0],' . $linkOptions . ',' . $customOptions . ');'), $text);
- }
- /**
- * @param string $email
- * @param options:
- * - obfuscate: true/false (defaults to false)
- * @return string html
- */
- public static function prepareEmail($email, $options = array(), $customOptions = array()) {
- $obfuscate = false;
- if (isset($options['obfuscate'])) {
- $obfuscate = $options['obfuscate'];
- unset($options['obfuscate']);
- }
- if (!isset($customOptions['escape']) || $customOptions['escape'] !== false) {
- $email = hDec($email);
- }
- $Html = new HtmlHelper(new View(null));
- //$Html->tags = $Html->loadConfig();
- //debug($Html->tags);
- if (!$obfuscate) {
- return $Html->link($email, "mailto:" . $email, $options);
- }
- $class = __CLASS__;
- $Common = new $class;
- $Common->Html = $Html;
- return $Common->encodeEmailUrl($email, null, array(), $options);
- }
- /**
- * Helper Function to Obfuscate Email by inserting a span tag (not more! not very secure on its own...)
- * each part of this mail now does not make sense anymore on its own
- * (striptags will not work either)
- * @param string email: necessary (and valid - containing one @)
- * @return string html
- */
- public function encodeEmail($mail) {
- list($mail1, $mail2) = explode('@', $mail);
- $encMail = $this->encodeText($mail1) . '<span>@</span>' . $this->encodeText($mail2);
- return $encMail;
- }
- /**
- * Obfuscates Email (works without JS!) to avoid lowlevel spam bots to get it
- * @param string mail: email to encode
- * @param string text: optional (if none is given, email will be text as well)
- * @param array attributes: html tag attributes
- * @param array params: ?subject=y&body=y to be attached to "mailto:xyz"
- * @return string html with js generated link around email (and non js fallback)
- */
- public function encodeEmailUrl($mail, $text=null, $params=array(), $attr = array()) {
- if (empty($class)) {
- $class = 'email';
- }
- $defaults = array(
- 'title' => __('for use in an external mail client'),
- 'class' => 'email',
- 'escape' => false
- );
- if (empty($text)) {
- $text = $this->encodeEmail($mail);
- }
- $encMail = 'mailto:' . $mail;
- //$encMail = $this->encodeText($encMail); # not possible
- // additionally there could be a span tag in between: email<span syle="display:none"></span>@web.de
- $querystring = '';
- foreach ($params as $key => $val) {
- if ($querystring) {
- $querystring .= "&$key=" . rawurlencode($val);
- } else {
- $querystring = "?$key=" . rawurlencode($val);
- }
- }
- $attr = array_merge($defaults, $attr);
- $xmail = $this->Html->link('', $encMail . $querystring, $attr);
- $xmail1 = mb_substr($xmail, 0, count($xmail) - 5);
- $xmail2 = mb_substr($xmail, -4, 4);
- $len = mb_strlen($xmail1);
- $i = 0;
- while ($i < $len) {
- $c = mt_rand(2, 6);
- $par[] = (mb_substr($xmail1, $i, $c));
- $i += $c;
- }
- $join = implode('\'+\'', $par);
- return '<script language=javascript><!--
- document.write(\'' . $join . '\');
- //--></script>
- ' . $text . '
- <script language=javascript><!--
- document.write(\'' . $xmail2 . '\');
- //--></script>';
- //return '<a class="'.$class.'" title="'.$title.'" href="'.$encmail.$querystring.'">'.$encText.'</a>';
- }
- /**
- * Encodes Piece of Text (without usage of JS!) to avoid lowlevel spam bots to get it
- * @param STRING text to encode
- * @return string html (randomly encoded)
- */
- public static function encodeText($text) {
- $encmail = '';
- $length = mb_strlen($text);
- for ($i = 0; $i < $length; $i++) {
- $encMod = mt_rand(0, 2);
- switch ($encMod) {
- case 0: // None
- $encmail .= mb_substr($text, $i, 1);
- break;
- case 1: // Decimal
- $encmail .= "&#" . ord(mb_substr($text, $i, 1)) . ';';
- break;
- case 2: // Hexadecimal
- $encmail .= "&#x" . dechex(ord(mb_substr($text, $i, 1))) . ';';
- break;
- }
- }
- return $encmail;
- }
- /**
- * Fix to allow shortened urls that do not break layout etc
- *
- * @param string $text
- * @param options (additionally - not yet supported by core):
- * - stripProtocol: bool (defaults to true)
- * - maxLength: int (defaults no none)
- * @param htmlOptions
- * - escape etc
- * @return string html
- * @override
- */
- public function autoLinkUrls($text, $options = array(), $htmlOptions = array()) {
- if (!isset($options['escape']) || $options['escape'] !== false) {
- $text = h($text);
- $matchString = 'hDec($matches[0])';
- } else {
- $matchString = '$matches[0]';
- }
- if (isset($htmlOptions['escape'])) {
- $options['escape'] = $htmlOptions['escape'];
- }
- //$htmlOptions['escape'] = false;
- $htmlOptions = var_export($htmlOptions, true);
- $customOptions = var_export($options, true);
- $text = preg_replace_callback('#(?<!href="|">)((?:https?|ftp|nntp)://[^\s<>()]+)#i', create_function('$matches',
- '$Html = new HtmlHelper(new View(null)); return $Html->link(TextExtHelper::prepareLinkName(hDec($matches[0]), ' . $customOptions . '), hDec($matches[0]),' . $htmlOptions . ');'), $text);
- return preg_replace_callback('#(?<!href="|">)(?<!http://|https://|ftp://|nntp://)(www\.[^\n\%\ <]+[^<\n\%\,\.\ <])(?<!\))#i',
- create_function('$matches', '$Html = new HtmlHelper(new View(null)); return $Html->link(TextExtHelper::prepareLinkName(hDec($matches[0]), ' . $customOptions . '), "http://" . hDec($matches[0]),' . $htmlOptions . ');'), $text);
- }
- /**
- * @param string $link
- * @param options:
- * - stripProtocol: bool (defaults to true)
- * - maxLength: int (defaults to 50)
- * - escape (defaults to false, true needed for hellip to work)
- * @return string html/$plain
- */
- public static function prepareLinkName($link, $options = array()) {
- # strip protocol if desired (default)
- if (!isset($options['stripProtocol']) || $options['stripProtocol'] !== false) {
- $link = self::stripProtocol($link);
- }
- if (!isset($options['maxLength'])) {
- $options['maxLength'] = 50; # should be long enough for most cases
- }
- # shorten display name if desired (default)
- if (!empty($options['maxLength']) && mb_strlen($link) > $options['maxLength']) {
- $link = mb_substr($link, 0, $options['maxLength']);
- # problematic with autoLink()
- if (!empty($options['html']) && isset($options['escape']) && $options['escape'] === false) {
- $link .= '…'; # only possible with escape => false!
- } else {
- $link .= '...';
- }
- }
- return $link;
- }
- /**
- * Remove http:// or other protocols from the link
- *
- * @param string $url
- * @return string strippedUrl
- */
- public static function stripProtocol($url) {
- $pieces = parse_url($url);
- if (empty($pieces['scheme'])) {
- return $url; # already stripped
- }
- return mb_substr($url, mb_strlen($pieces['scheme']) + 3); # +3 <=> :// # can only be 4 with "file" (file:///)...
- }
- /**
- * Minimizes the given url to a maximum length
- *
- * @param string $url the url
- * @param integer $max the maximum length
- * @param array $options
- * - placeholder
- * @return string the manipulated url (+ eventuell ...)
- */
- public function minimizeUrl($url = null, $max = null, $options = array()) {
- // check if there is nothing to do
- if (empty($url) || mb_strlen($url) <= (int)$max) {
- return (string)$url;
- }
- // http:// has not to be displayed, so
- if (mb_substr($url, 0, 7) === 'http://') {
- $url = mb_substr($url, 7);
- }
- // cut the parameters
- if (mb_strpos($url, '/') !== false) {
- $url = strtok($url, '/');
- }
- // return if the url is short enough
- if (mb_strlen($url) <= (int)$max) {
- return $url;
- }
- // otherwise cut a part in the middle (but only if long enough!!!)
- # TODO: more dynamically
- $placeholder = CHAR_HELLIP;
- if (!empty($options['placeholder'])) {
- $placeholder = $options['placeholder'];
- }
- $end = mb_substr($url, -5, 5);
- $front = mb_substr($url, 0, (int)$max - 8);
- return $front . $placeholder . $end;
- }
- /**
- * Transforming int values into ordinal numbers (1st, 3rd, etc.)
- * @param $num (INT) - the number to be suffixed.
- * @param $sup (BOOL) - whether to wrap the suffix in a superscript (<sup>) tag on output.
- * @return string ordinal
- */
- public static function ordinalNumber($num = 0, $sup = false) {
- $suff = '';
- if (!in_array(($num % 100), array(11, 12, 13))) {
- switch ($num % 10) {
- case 1:
- $suff = 'st';
- break;
- case 2:
- $suff = 'nd';
- break;
- case 3:
- $suff = 'rd';
- break;
- default:
- $suff = 'th';
- }
- }
- return ($sup) ? $num . '<sup>' . $suff . '</sup>' : $num . $suff;
- }
- /**
- * Syntax highlighting using php internal highlighting
- * @param string $filename
- * @param boolean $return (else echo directly)
- */
- public static function highlightFile($file, $return = true) {
- return highlight_file($file, $return);
- }
- /**
- * Syntax highlighting using php internal highlighting
- * @param string $contentstring
- * @param boolean $return (else echo directly)
- */
- public static function highlightString($string, $return = true) {
- return highlight_string($string, $return);
- }
- }
|