cakephp2-php8/cake/libs/flay.php

366 lines
10 KiB
PHP
Raw Normal View History

<?php
/* SVN FILE: $Id$ */
/**
* Text-to-HTML parser.
*
* Text-to-html parser, similar to {@link http://textism.com/tools/textile/ Textile} or {@link http://www.whytheluckystiff.net/ruby/redcloth/ RedCloth}.
*
* PHP versions 4 and 5
*
* CakePHP : Rapid Development Framework <http://www.cakephp.org/>
* Copyright (c) 2005, CakePHP Authors/Developers
*
* Author(s): Michal Tatarynowicz aka Pies <tatarynowicz@gmail.com>
* Larry E. Masters aka PhpNut <nut@phpnut.com>
* Kamil Dzielinski aka Brego <brego.dk@gmail.com>
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @filesource
* @author CakePHP Authors/Developers
* @copyright Copyright (c) 2005, CakePHP Authors/Developers
* @link https://trac.cakephp.org/wiki/Authors Authors/Developers
* @package cake
Merging from sandboxes [1079] Merged [1005] committed by nate but not added to core prior to release. Merged [1078] prior to modifying all developers sandboxes. [1081] adding view and template directories [1082] adding base files for view generator [1083] correcting all package and sub package tags for in doc blocks. Making sure every file in the core has doc block in them [1084] renaming working copy of latest release [1093] Added fix for associations using underscores if var $useTable is set in the associated models. This closes ticket #11. [1094] Fix for Ticket #24. The problem was tracked to a variable in View::_render(); $loadedHelpers was being assigned a reference when it when it should not have been. [1096] Initial work on controller components needs testing. Also added a work around for the basics.php uses(). Using the define DS where the files from the original version are now located in deeper libs directories. [1097] committing a few typos in the code I added [1098] reformatting code in component.php [1104] changed the test route and corrected a regex in inflector. [1111] removing the contructor from dispatcher, it is not needed [1112] Changes made for errors when a file is not present in webroot. Fixed the regex used in Router::parse(). Change the error layout template. [1113] Changes to Folder class to allow setting the permissions mode when constructing. This class needs to be refactored and move everything that is in the contructor out. The constructor should set the vars for use in other Folder::"methods"(). Will work on this at a later time. git-svn-id: https://svn.cakephp.org/repo/trunk/cake@1114 3807eeeb-6ff5-0310-8944-8be069107fe0
2005-10-09 01:56:21 +00:00
* @subpackage cake.cake.libs
* @since CakePHP v 0.2.9
* @version $Revision$
* @modifiedby $LastChangedBy$
* @lastmodified $Date$
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
/**
* Included libraries.
*/
uses('object');
/**
* Text-to-HTML parser.
*
* Text-to-html parser, similar to Textile or RedCloth, only with a little different syntax.
*
* @package cake
Merging from sandboxes [1079] Merged [1005] committed by nate but not added to core prior to release. Merged [1078] prior to modifying all developers sandboxes. [1081] adding view and template directories [1082] adding base files for view generator [1083] correcting all package and sub package tags for in doc blocks. Making sure every file in the core has doc block in them [1084] renaming working copy of latest release [1093] Added fix for associations using underscores if var $useTable is set in the associated models. This closes ticket #11. [1094] Fix for Ticket #24. The problem was tracked to a variable in View::_render(); $loadedHelpers was being assigned a reference when it when it should not have been. [1096] Initial work on controller components needs testing. Also added a work around for the basics.php uses(). Using the define DS where the files from the original version are now located in deeper libs directories. [1097] committing a few typos in the code I added [1098] reformatting code in component.php [1104] changed the test route and corrected a regex in inflector. [1111] removing the contructor from dispatcher, it is not needed [1112] Changes made for errors when a file is not present in webroot. Fixed the regex used in Router::parse(). Change the error layout template. [1113] Changes to Folder class to allow setting the permissions mode when constructing. This class needs to be refactored and move everything that is in the contructor out. The constructor should set the vars for use in other Folder::"methods"(). Will work on this at a later time. git-svn-id: https://svn.cakephp.org/repo/trunk/cake@1114 3807eeeb-6ff5-0310-8944-8be069107fe0
2005-10-09 01:56:21 +00:00
* @subpackage cake.cake.libs
* @since CakePHP v 0.2.9
*/
class Flay extends Object
{
/**
* Text to be parsed.
*
* @var string
*/
var $text = null;
/**
* Set this to allow HTML in the markup.
*
* @var boolean
*/
var $allow_html = false;
/**
* Constructor.
*
* @param string $text
*/
function __construct ($text=null)
{
$this->text = $text;
parent::__construct();
}
/**
* Returns given text translated to HTML using the Flay syntax.
*
* @param string $text String to format
* @param boolean $bare Set this to only do <p> transforms and > to &gt;, no typography additions.
* @param boolean $allowHtml Set this to trim whitespace and disable all HTML
* @return string Formatted text
*/
function toHtml ($text=null, $bare=false, $allowHtml=false)
{
if (empty($text) && empty($this->text))
{
return false;
}
$text = $text? $text: $this->text;
// trim whitespace and disable all HTML
if ($allowHtml)
{
$text = trim($text);
}
else
{
$text = str_replace('<', '&lt;', str_replace('>', '&gt;', trim($text)));
}
if (!$bare)
{
// multi-paragraph functions
$text = preg_replace('#(?:[\n]{0,2})"""(.*)"""(?:[\n]{0,2})#s', "\n\n%BLOCKQUOTE%\n\n\\1\n\n%ENDBLOCKQUOTE%\n\n", $text);
$text = preg_replace('#(?:[\n]{0,2})===(.*)===(?:[\n]{0,2})#s', "\n\n%CENTER%\n\n\\1\n\n%ENDCENTER%\n\n", $text);
}
// pre-parse newlines
$text = preg_replace("#\r\n#", "\n", $text);
$text = preg_replace("#[\n]{2,}#", "%PARAGRAPH%", $text);
$text = preg_replace('#[\n]{1}#', "%LINEBREAK%", $text);
// split into paragraphs and parse
$out = '';
foreach (split('%PARAGRAPH%', $text) as $line)
{
if ($line)
{
if (!$bare)
{
// pre-parse links
$links = array();
$regs = null;
if (preg_match_all('#\[([^\[]{4,})\]#', $line, $regs))
{
foreach ($regs[1] as $reg)
{
$links[] = $reg;
$line = str_replace("[{$reg}]",'%LINK'.(count($links)-1).'%', $line);
}
}
// MAIN TEXT FUNCTIONS
// bold
$line = ereg_replace("\*([^\*]*)\*", "<strong>\\1</strong>", $line);
// italic
$line = ereg_replace("_([^_]*)_", "<em>\\1</em>", $line);
}
// entities
$line = str_replace(' - ', ' &ndash; ', $line);
$line = str_replace(' -- ', ' &mdash; ', $line);
$line = str_replace('(C)', '&copy;', $line);
$line = str_replace('(R)', '&reg;', $line);
$line = str_replace('(TM)', '&trade;', $line);
// guess e-mails
$emails = null;
if (preg_match_all("#([_A-Za-z0-9+-+]+(?:\.[_A-Za-z0-9+-]+)*@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*)#", $line, $emails))
{
foreach ($emails[1] as $email)
{
$line = str_replace($email, "<a href=\"mailto:{$email}\">{$email}</a>", $line);
}
}
if (!$bare)
{
// guess links
$urls = null;
if (preg_match_all("#((?:http|https|ftp|nntp)://[^ ]+)#", $line, $urls))
{
foreach ($urls[1] as $url)
{
$line = str_replace($url, "<a href=\"{$url}\">{$url}</a>", $line);
}
}
if (preg_match_all("#(www\.[^\n\%\ ]+[^\n\%\,\.\ ])#", $line, $urls))
{
foreach ($urls[1] as $url)
{
$line = str_replace($url, "<a href=\"http://{$url}\">{$url}</a>", $line);
}
}
// re-parse links
if (count($links))
{
for ($ii=0; $ii<count($links); $ii++)
{
if (preg_match("#^(http|https|ftp|nntp)://#", $links[$ii]))
{
$prefix = null;
}
else
{
$prefix = 'http://';
}
if (preg_match('#^[^\ ]+\.(jpg|jpeg|gif|png)$#', $links[$ii]))
{
$with = "<img src=\"{$prefix}{$links[$ii]}\" alt=\"\" />";
}
elseif (preg_match('#^([^\]\ ]+)(?:\ ([^\]]+))?$#', $links[$ii], $regs))
{
if (isset($regs[2]))
{
if (preg_match('#\.(jpg|jpeg|gif|png)$#', $regs[2]))
{
$body = "<img src=\"{$prefix}{$regs[2]}\" alt=\"\" />";
}
else
{
$body = $regs[2];
}
}
else
{
$body = $links[$ii];
}
$with = "<a href=\"{$prefix}{$regs[1]}\" target=\"_blank\">{$body}</a>";
}
else
{
$with = $prefix.$links[$ii];
}
$line = str_replace("%LINK{$ii}%", $with, $line);
}
}
}
// re-parse newlines
$out .= str_replace('%LINEBREAK%', "<br />\n", "<p>{$line}</p>\n");
}
}
if (!$bare)
{
// re-parse multilines
$out = str_replace('<p>%BLOCKQUOTE%</p>', "<blockquote>", $out);
$out = str_replace('<p>%ENDBLOCKQUOTE%</p>', "</blockquote>", $out);
$out = str_replace('<p>%CENTER%</p>', "<center>", $out);
$out = str_replace('<p>%ENDCENTER%</p>', "</center>", $out);
}
return $out;
}
/**
* Return the words of the string as an array.
*
* @param string $string
* @return array Array of words
*/
function extractWords ($string)
{
return preg_split('/[\s,\.:\/="!\(\)<>~\[\]]+/', $string);
}
/**
* Return given string with words in array colorMarked, up to a number of times (defaults to 5).
*
* @param array $words Words to look for and markup
* @param string $string String to look in
* @param integer $max_snippets Max number of snippets to extract
* @return string
* @see colorMark
*/
function markedSnippets ($words, $string, $max_snippets=5)
{
$string = strip_tags($string);
$snips = array();
$rest = $string;
foreach ($words as $word)
{
if (preg_match_all("/[\s,]+.{0,40}{$word}.{0,40}[\s,]+/i", $rest, $r))
{
foreach ($r as $result)
{
$rest = str_replace($result, '', $rest);
}
$snips = array_merge($snips, $r[0]);
}
}
if (count($snips) > $max_snippets)
{
$snips = array_slice($snips, 0, $max_snippets);
}
$joined = join(' <b>...</b> ', $snips);
$snips = $joined? "<b>...</b> {$joined} <b>...</b>": substr($string, 0, 80) . '<b>...</b>';
return Flay::colorMark($words, $snips);
}
/**
* Returns string with EM elements with color classes added.
*
* @param array $words Array of words to be colorized
* @param string $string Text in which the words might be found
* @return string
*/
function colorMark($words, $string)
{
$colors = array('yl','gr','rd','bl','fu','cy');
$nextColorIndex = 0;
foreach ($words as $word)
{
$string = preg_replace("/({$word})/i", '<em class="' . $colors[$nextColorIndex%count($colors)] . "\">\\1</em>", $string);
$nextColorIndex++;
}
return $string;
}
/**
* Returns given text with tags stripped out.
*
* @param string $text
* @return string
*/
function toClean ($text)
{
return strip_tags(html_entity_decode($text, ENT_QUOTES));
}
/**
* Return parsed text with tags stripped out.
*
* @param string $text
* @return string
*/
function toParsedAndClean ($text)
{
return Flay::toClean(Flay::toHtml($text));
}
/**
* Return a fragment of a text, up to $length characters long, with an ellipsis after it.
*
* @param string $text Text to be truncated.
* @param integer $length Max length of text.
* @param string $ellipsis Sign to print after truncated text.
* @return string
*/
function fragment ($text, $length, $ellipsis='...')
{
$soft = $length - 5;
$hard = $length + 5;
$rx = '/(.{' . $soft . ',' . $hard . '})[\s,\.:\/="!\(\)<>~\[\]]+.*/';
if (preg_match($rx, $text, $r))
{
$out = $r[1];
}
else
{
$out = substr($text, 0, $length);
}
$out = $out . (strlen($out)<strlen($text)? $ellipsis: null);
return $out;
}
}
?>