1<?php
2/*
3 * Gallery - a web based photo album viewer and editor
4 * Copyright (C) 2000-2008 Bharat Mediratta
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21/*
22 * Smarty plugin
23 * -------------------------------------------------------------
24 * Type:     modifier
25 * Name:     markup
26 * Purpose:  Format embedded markup in the given string according
27 *           to settings specified in site admin (no markup, bbcode or
28 *           raw html)
29 * -------------------------------------------------------------
30 */
31function smarty_modifier_markup($text) {
32    static $parsers = array();
33    static $cacheKey = 'smarty_modifier_markup';
34
35    $stripTags = false;
36    $args = func_get_args();
37    array_shift($args);
38    foreach ($args as $arg) {
39	if ($arg == 'strip') {
40	    $stripTags = true;
41	} else {
42	    $markupType = $arg;
43	}
44    }
45    if (!isset($markupType)) {
46	if (!GalleryDataCache::containsKey($cacheKey)) {
47	    list ($ret, $defaultMarkupType) =
48		GalleryCoreApi::getPluginParameter('module', 'core', 'misc.markup');
49	    if ($ret) {
50		/* This code is used by the UI -- we can't return an error. Choose something safe */
51		$defaultMarkupType = 'none';
52	    }
53	    GalleryDataCache::put($cacheKey, $defaultMarkupType);
54	}
55
56	$markupType = GalleryDataCache::get($cacheKey);
57    }
58
59    if (!isset($parsers[$markupType])) {
60	switch($markupType) {
61	case 'bbcode':
62	    $parsers[$markupType] = new GalleryBbcodeMarkupParser();
63	    break;
64
65	case 'html':
66	    $parsers[$markupType] = new GalleryHtmlMarkupParser();
67	    break;
68
69	case 'none':
70	default:
71	    $parsers[$markupType] = new GalleryNoMarkupParser();
72	}
73    }
74
75    $text = $parsers[$markupType]->parse($text);
76    return $stripTags ? strip_tags($text) : $text;
77}
78
79class GalleryNoMarkupParser {
80    function parse($text) {
81	return $text;
82    }
83}
84
85class GalleryHtmlMarkupParser {
86    function parse($text) {
87	/* http://bugs.php.net/bug.php?id=22014 - TODO: remove empty check when min php is 4.3.2+ */
88	return empty($text) ? $text : GalleryUtilities::htmlSafe(html_entity_decode($text));
89    }
90}
91
92class GalleryBbcodeMarkupParser {
93    var $_bbcode;
94
95    function GalleryBbcodeMarkupParser() {
96	if (!class_exists('StringParser_BBCode')) {
97	    GalleryCoreApi::requireOnce('lib/bbcode/stringparser_bbcode.class.php');
98	}
99
100	$this->_bbcode = new StringParser_BBCode();
101	$this->_bbcode->setGlobalCaseSensitive(false);
102
103	/* Convert line breaks everywhere */
104	$this->_bbcode->addParser(array('block', 'inline', 'link', 'listitem', 'list'),
105				  array($this, 'convertLineBreaks'));
106
107	/*
108	 * Escape all characters everywhere
109	 * We don't need to do this 'cause G2 doesn't allow raw entities into the database
110	 * $this->_bbcode->addParser('htmlspecialchars',
111	 *			     array('block', 'inline', 'link', 'listitem'));
112	 */
113
114	/* Convert line endings */
115	$this->_bbcode->addParser(array('block', 'inline', 'link', 'listitem'), 'nl2br');
116
117	/* Strip last line break in list items */
118	$this->_bbcode->addParser(array('listitem'), array($this, 'stripLastLineBreak'));
119
120	/* Strip contents in list elements */
121	$this->_bbcode->addParser(array('list'), array($this, 'stripContents'));
122
123	/* [b], [i] */
124	$this->_bbcode->addCode('b', 'simple_replace', null,
125				array('start_tag' => '<b>', 'end_tag' => '</b>'),
126				'inline', array('listitem', 'block', 'inline', 'link'), array());
127
128	$this->_bbcode->addCode('i', 'simple_replace', null,
129				array('start_tag' => '<i>', 'end_tag' => '</i>'),
130				'inline', array('listitem', 'block', 'inline', 'link'), array());
131
132	/* [url]http://...[/url], [url=http://...]Text[/url] */
133	$this->_bbcode->addCode('url', 'usecontent?', array($this, 'url'),
134			 array('usecontent_param' => 'default'),
135			 'link', array('listitem', 'block', 'inline'), array('link'));
136
137	/* [color=...]Text[/color] */
138	$this->_bbcode->addCode('color', 'callback_replace', array($this, 'color'),
139			 array('usecontent_param' => 'default'),
140			 'inline', array('listitem', 'block', 'inline', 'link'), array());
141
142	/* [img]http://...[/img] */
143	$this->_bbcode->addCode('img', 'usecontent', array($this, 'image'), array(),
144			 'image', array('listitem', 'block', 'inline', 'link'), array());
145
146	/* [list] [*]Element [/list] */
147	$this->_bbcode->addCode('list', 'simple_replace', null,
148				array('start_tag' => '<ul>', 'end_tag' => '</ul>'),
149				'list', array('block', 'listitem'), array());
150	$this->_bbcode->addCode('*', 'simple_replace', null,
151				array('start_tag' => '<li>', 'end_tag' => "</li>\n"),
152				'listitem', array('list'), array());
153	$this->_bbcode->setCodeFlag('*', 'closetag', BBCODE_CLOSETAG_OPTIONAL);
154    }
155
156    function parse($text) {
157	return $this->_bbcode->parse($text);
158    }
159
160    function url($action, $attributes, $content, $params, &$node_object) {
161	if ($action == 'validate') {
162	    /* The code is like [url]http://.../[/url] */
163	    if (!isset($attributes['default'])) {
164		return preg_match('#^(https?|ftp|mailto):|^/#', $content);
165	    } else {
166		/* The code is like [url=http://.../]Text[/url] */
167		return preg_match('#^(https?|ftp|mailto):|^/#', $attributes['default']);
168	    }
169	} else {
170	    /* Output of HTML. */
171	    /* The code is like [url]http://.../[/url] */
172	    if (!isset($attributes['default'])) {
173		return '<a href="' . $content . '" rel="nofollow">' . $content . '</a>';
174	    } else {
175		/* The code is like [url=http://.../]Text[/url] */
176		return '<a href="' . $attributes['default'] . '" rel="nofollow">'
177		    . $content . '</a>';
178	    }
179	}
180    }
181
182    function image($action, $attrs, $content, $params, &$node_object) {
183	if ($action == 'validate') {
184	    return preg_match('#^(https?|ftp|mailto):|^/#', $content);
185	} else {
186	    /* Output of HTML. */
187	    $size = (isset($attrs['width']) ? ' width="' . (int)$attrs['width'] . '"' : '')
188		. (isset($attrs['height']) ? ' height="' . (int)$attrs['height'] . '"' : '');
189	    /* Input should have entities already, so no htmlspecialchars here */
190	    return sprintf('<img src="%s" alt=""%s/>', $content, $size);
191	}
192    }
193
194    function color($action, $attrs, $content, $params, &$node_object) {
195	if ($action == 'validate') {
196	    return !empty($attrs['default']);
197	} else {
198	    /* Output of HTML. */
199	    $color = empty($attrs) ? 'bummer' : $attrs['default'];
200	    return sprintf('<font color="%s">%s</font>', $color, $content);
201	}
202    }
203
204    function convertLineBreaks($text) {
205	return preg_replace("/\015\012|\015|\012/", "\n", $text);
206    }
207
208    function stripContents($text) {
209	return preg_replace("/[^\n]/", '', $text);
210    }
211
212    function stripLastLineBreak ($text) {
213	return preg_replace("/\n( +)?$/", '$1', $text);
214    }
215}
216?>
217