diff -r 5b37998e522e -r 162c1de6545a web/lib/Zend/Markup/Renderer/Html.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/lib/Zend/Markup/Renderer/Html.php Fri Mar 11 15:05:35 2011 +0100 @@ -0,0 +1,528 @@ + array('block', 'inline', 'block-empty', 'inline-empty', 'list'), + 'inline' => array('inline', 'inline-empty'), + 'list' => array('list-item'), + 'list-item' => array('inline', 'inline-empty', 'list'), + 'block-empty' => array(), + 'inline-empty' => array(), + ); + + /** + * The current group + * + * @var string + */ + protected $_group = 'block'; + + /** + * Default attributes + * + * @var array + */ + protected static $_defaultAttributes = array( + 'id' => '', + 'class' => '', + 'style' => '', + 'lang' => '', + 'title' => '' + ); + + + /** + * Constructor + * + * @param array|Zend_Config $options + * + * @return void + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + $this->_pluginLoader = new Zend_Loader_PluginLoader(array( + 'Zend_Markup_Renderer_Html' => 'Zend/Markup/Renderer/Html/' + )); + + if (!isset($options['useDefaultMarkups']) && isset($options['useDefaultTags'])) { + $options['useDefaultMarkups'] = $options['useDefaultTags']; + } + if (isset($options['useDefaultMarkups']) && ($options['useDefaultMarkups'] !== false)) { + $this->_defineDefaultMarkups(); + } elseif (!isset($options['useDefaultMarkups'])) { + $this->_defineDefaultMarkups(); + } + + parent::__construct($options); + } + + /** + * Define the default markups + * + * @return void + */ + protected function _defineDefaultMarkups() + { + $this->_markups = array( + 'b' => array( + 'type' => 10, // self::TYPE_REPLACE | self::TAG_NORMAL + 'tag' => 'strong', + 'group' => 'inline', + 'filter' => true, + ), + 'u' => array( + 'type' => 10, + 'tag' => 'span', + 'attributes' => array( + 'style' => 'text-decoration: underline;', + ), + 'group' => 'inline', + 'filter' => true, + ), + 'i' => array( + 'type' => 10, + 'tag' => 'em', + 'group' => 'inline', + 'filter' => true, + ), + 'cite' => array( + 'type' => 10, + 'tag' => 'cite', + 'group' => 'inline', + 'filter' => true, + ), + 'del' => array( + 'type' => 10, + 'tag' => 'del', + 'group' => 'inline', + 'filter' => true, + ), + 'ins' => array( + 'type' => 10, + 'tag' => 'ins', + 'group' => 'inline', + 'filter' => true, + ), + 'sub' => array( + 'type' => 10, + 'tag' => 'sub', + 'group' => 'inline', + 'filter' => true, + ), + 'sup' => array( + 'type' => 10, + 'tag' => 'sup', + 'group' => 'inline', + 'filter' => true, + ), + 'span' => array( + 'type' => 10, + 'tag' => 'span', + 'group' => 'inline', + 'filter' => true, + ), + 'acronym' => array( + 'type' => 10, + 'tag' => 'acronym', + 'group' => 'inline', + 'filter' => true, + ), + // headings + 'h1' => array( + 'type' => 10, + 'tag' => 'h1', + 'group' => 'inline', + 'filter' => true, + ), + 'h2' => array( + 'type' => 10, + 'tag' => 'h2', + 'group' => 'inline', + 'filter' => true, + ), + 'h3' => array( + 'type' => 10, + 'tag' => 'h3', + 'group' => 'inline', + 'filter' => true, + ), + 'h4' => array( + 'type' => 10, + 'tag' => 'h4', + 'group' => 'inline', + 'filter' => true, + ), + 'h5' => array( + 'type' => 10, + 'tag' => 'h5', + 'group' => 'inline', + 'filter' => true, + ), + 'h6' => array( + 'type' => 10, + 'tag' => 'h6', + 'group' => 'inline', + 'filter' => true, + ), + // callback tags + 'url' => array( + 'type' => 6, // self::TYPE_CALLBACK | self::TAG_NORMAL + 'callback' => null, + 'group' => 'inline', + 'filter' => true, + ), + 'img' => array( + 'type' => 6, + 'callback' => null, + 'group' => 'inline-empty', + 'filter' => true, + ), + 'code' => array( + 'type' => 6, + 'callback' => null, + 'group' => 'block-empty', + 'filter' => false, + ), + 'p' => array( + 'type' => 10, + 'tag' => 'p', + 'group' => 'block', + 'filter' => true, + ), + 'ignore' => array( + 'type' => 10, + 'start' => '', + 'end' => '', + 'group' => 'block-empty', + 'filter' => true, + ), + 'quote' => array( + 'type' => 10, + 'tag' => 'blockquote', + 'group' => 'block', + 'filter' => true, + ), + 'list' => array( + 'type' => 6, + 'callback' => null, + 'group' => 'list', + 'filter' => new Zend_Filter_PregReplace('/.*/is', ''), + ), + '*' => array( + 'type' => 10, + 'tag' => 'li', + 'group' => 'list-item', + 'filter' => true, + ), + 'hr' => array( + 'type' => 9, // self::TYPE_REPLACE | self::TAG_SINGLE + 'tag' => 'hr', + 'group' => 'block', + 'empty' => true, + ), + // aliases + 'bold' => array( + 'type' => 16, + 'name' => 'b', + ), + 'strong' => array( + 'type' => 16, + 'name' => 'b', + ), + 'italic' => array( + 'type' => 16, + 'name' => 'i', + ), + 'em' => array( + 'type' => 16, + 'name' => 'i', + ), + 'emphasized' => array( + 'type' => 16, + 'name' => 'i', + ), + 'underline' => array( + 'type' => 16, + 'name' => 'u', + ), + 'citation' => array( + 'type' => 16, + 'name' => 'cite', + ), + 'deleted' => array( + 'type' => 16, + 'name' => 'del', + ), + 'insert' => array( + 'type' => 16, + 'name' => 'ins', + ), + 'strike' => array( + 'type' => 16, + 'name' => 's', + ), + 's' => array( + 'type' => 16, + 'name' => 'del', + ), + 'subscript' => array( + 'type' => 16, + 'name' => 'sub', + ), + 'superscript' => array( + 'type' => 16, + 'name' => 'sup', + ), + 'a' => array( + 'type' => 16, + 'name' => 'url', + ), + 'image' => array( + 'type' => 16, + 'name' => 'img', + ), + 'li' => array( + 'type' => 16, + 'name' => '*', + ), + 'color' => array( + 'type' => 16, + 'name' => 'span', + ), + ); + } + + /** + * Add the default filters + * + * @return void + */ + public function addDefaultFilters() + { + $this->_defaultFilter = new Zend_Filter(); + + $this->_defaultFilter->addFilter(new Zend_Filter_HtmlEntities(array('encoding' => self::getEncoding()))); + $this->_defaultFilter->addFilter(new Zend_Filter_Callback('nl2br')); + } + + /** + * Execute a replace token + * + * @param Zend_Markup_Token $token + * @param array $markup + * @return string + */ + protected function _executeReplace(Zend_Markup_Token $token, $markup) + { + if (isset($markup['tag'])) { + if (!isset($markup['attributes'])) { + $markup['attributes'] = array(); + } + $attrs = self::renderAttributes($token, $markup['attributes']); + return "<{$markup['tag']}{$attrs}>{$this->_render($token)}"; + } + + return parent::_executeReplace($token, $markup); + } + + /** + * Execute a single replace token + * + * @param Zend_Markup_Token $token + * @param array $markup + * @return string + */ + protected function _executeSingleReplace(Zend_Markup_Token $token, $markup) + { + if (isset($markup['tag'])) { + if (!isset($markup['attributes'])) { + $markup['attributes'] = array(); + } + $attrs = self::renderAttributes($token, $markup['attributes']); + return "<{$markup['tag']}{$attrs} />"; + } + return parent::_executeSingleReplace($token, $markup); + } + + /** + * Render some attributes + * + * @param Zend_Markup_Token $token + * @param array $attributes + * @return string + */ + public static function renderAttributes(Zend_Markup_Token $token, array $attributes = array()) + { + $attributes = array_merge(self::$_defaultAttributes, $attributes); + + $return = ''; + + $tokenAttributes = $token->getAttributes(); + + // correct style attribute + if (isset($tokenAttributes['style'])) { + $tokenAttributes['style'] = trim($tokenAttributes['style']); + + if ($tokenAttributes['style'][strlen($tokenAttributes['style']) - 1] != ';') { + $tokenAttributes['style'] .= ';'; + } + } else { + $tokenAttributes['style'] = ''; + } + + // special treathment for 'align' and 'color' attribute + if (isset($tokenAttributes['align'])) { + $tokenAttributes['style'] .= 'text-align: ' . $tokenAttributes['align'] . ';'; + unset($tokenAttributes['align']); + } + if (isset($tokenAttributes['color']) && self::checkColor($tokenAttributes['color'])) { + $tokenAttributes['style'] .= 'color: ' . $tokenAttributes['color'] . ';'; + unset($tokenAttributes['color']); + } + + /* + * loop through all the available attributes, and check if there is + * a value defined by the token + * if there is no value defined by the token, use the default value or + * don't set the attribute + */ + foreach ($attributes as $attribute => $value) { + if (isset($tokenAttributes[$attribute]) && !empty($tokenAttributes[$attribute])) { + $return .= ' ' . $attribute . '="' . htmlentities($tokenAttributes[$attribute], + ENT_QUOTES, + self::getEncoding()) . '"'; + } elseif (!empty($value)) { + $return .= ' ' . $attribute . '="' . htmlentities($value, ENT_QUOTES, self::getEncoding()) . '"'; + } + } + + return $return; + } + + /** + * Check if a color is a valid HTML color + * + * @param string $color + * + * @return bool + */ + public static function checkColor($color) + { + /* + * aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, + * purple, red, silver, teal, white, and yellow. + */ + $colors = array( + 'aqua', 'black', 'blue', 'fuchsia', 'gray', 'green', 'lime', + 'maroon', 'navy', 'olive', 'purple', 'red', 'silver', 'teal', + 'white', 'yellow' + ); + + if (in_array($color, $colors)) { + return true; + } + + if (preg_match('/\#[0-9a-f]{6}/i', $color)) { + return true; + } + + return false; + } + + /** + * Check if the URI is valid + * + * @param string $uri + * + * @return bool + */ + public static function isValidUri($uri) + { + if (!preg_match('/^([a-z][a-z+\-.]*):/i', $uri, $matches)) { + return false; + } + + $scheme = strtolower($matches[1]); + + switch ($scheme) { + case 'javascript': + // JavaScript scheme is not allowed for security reason + return false; + + case 'http': + case 'https': + case 'ftp': + $components = @parse_url($uri); + + if ($components === false) { + return false; + } + + if (!isset($components['host'])) { + return false; + } + + return true; + + default: + return true; + } + } +}