geparster Text:
1
.<?php
2 /**
3 * BBParser
4 * parst Code auf konfigurierbare BBCode-Tags
5 *
6 * @author Johannes Schlichenmaier
7 * @version 01.03.2006
8 * @package core_util
9 */
10
11 class core_util_BBParser {
12 private $tags = array('search' => array(), 'replace' => array(), 'plc' => array(), 'allowed_in' => array(), 'allowed_within' => array());
13
14 /**
15 * core_util_BBParser::construct($custom = false)
16 * Erstellt auf Wunsch häufige BBCode-Tags automatisch. Wenn nicht erwünscht, einfach mit "true" als Parameter aufrufen.
17 *
18 * @param boolean $custom Wenn "true" gesetzt, werden b, i , u, und zwei Varianten von Links (link - [url=...]...[/url] -
19 * und url - [url]...[/url]- ) nicht erstellt.
20 */
21 public function __construct($custom = false) {
22 if ($custom === false) {
23 $this->add_Tag('b', '[b]%b[/b]', '<b>%b</b>');
24 $this->add_Tag('i', '[i]%i[/i]', '<i>%i</i>');
25 $this->add_Tag('u', '[u]%u[/u]', '<u>%u</u>');
26 $this->add_Tag('link', '[url=%s]%l[/url]', '<a href="%s">%l</a>');
27 $this->add_Tag('url', '[url]%s[/url]', '<a href="%s">%s</a>');
28 }
29 }
30
31
32 /**
33 * core_util_BBParser::prepare_Pattern($string)
34 * wandelt einen BBCode zu einem Regulären Ausdruck um
35 *
36 * @param String $string umzuwandelnder String
37 */
38 private function prepare_Pattern($string, $modifiers) {
39 $string = addcslashes($string,'\'\\/,^$.[]|()?*+{}');
40 $string = preg_replace("/%[a-z]/", "(.*)", $string);
41 $string = '/'.$string.'/'.$modifiers;
42 return $string;
43 }
44
45
46 /**
47 * core_util_BBParser::prepare_html_Output($string, $placeholders)
48 * bereitet den übergebenen HTML-Code mit den Platzhaltern für die Verwendung in preg_replace vor
49 *
50 * @param String $string umzuwandelnder HTML-Code
51 * @param Array $placeholders Array mit in dem BBCode gefundenen Platzhaltern in der Reihenfolge ihres Auftretens
52 */
53 private function prepare_html_Output($string, $placeholders) {
54 $i = 0;
55 $return = array("", array());
56 $return[0] = str_replace(array("'", "%\'"), array("\'", "'"), $string);
57 $return[0] = "'".$return[0]."'";
58 foreach ($placeholders as $index => $plc) {
59 $return[1][] = $index;
60 if ($plc !== null) {
61 $return[0] = str_replace($index, "'.".$plc."(str_replace('\\"', '"','\$".($i+1)."')).'", $return[0]);
62 }
63 else {
64 $return[0] = str_replace($index, "'.str_replace('\\"', '"', '\$".($i+1)."').'", $return[0]);
65 }
66 $i++;
67 }
68 return $return;
69 }
70
71
72 /**
73 * core_util_BBParser::is_valid_function_array(&$name)
74 * Überprüft, ob ein übergebenes Array mit Platzhaltern gültige Funktionen/Methoden enthält
75 *
76 * @param &Array $name Array mit Platzhaltern (und zusätzlichen Informationen)
77 */
78 private function is_valid_function_array(&$name) {
79 $all_valid = true;
80 foreach ($name as $plc => $function) {
81 $valid = true;
82 if (preg_match("/^%[a-z]/", $plc)) {
83 if (stristr($function, '$this->') !== false) {
84 $function_array = explode('->', $function);
85 if (!is_callable(array($this, $function_array[1]))) $valid = false;
86 }
87 elseif (strstr($function, '::') !== false) {
88 $function_array = explode('::', $function);
89 if (!is_callable(array("$function_array[0]", $function_array[1]))) $valid = false;
90 }
91 else {
92 if (!function_exists($function)) $valid = false;
93 }
94 if (!$valid) {
95 $all_valid = false;
96 $name[$plc] = $name[$plc].' - ERROR: method/function is not callable';
97 }
98 }
99 }
100
101 return $all_valid;
102 }
103
104
105 /**
106 * core_util_BBParser::add_Tag($name, $bbcode, $htmlcode, $options = array())
107 * Fügt einen weiteren BBCode-Tag zum Suchalgorithmus hinzu
108 *
109 * Platzhalter: ein % mit anschließendem a-z.
110 * Besondere Platzhalter: %s : Darin gefundene Strings werden nicht weiter geparst - NOCH NICHT IMPLEMENTIERT
111 * %' : Wird im preg_replace später zu einem unescapten ' . Nützlich, um einzelne Platzhalter direkt durch Funktionen oder Methoden zu schicken.
112 *
113 * @param String $name Identifier des neuen Tags
114 * @param String $bbcode BBCode mit Platzhaltern
115 * @param String $htmlcode HTML-Code mit Platzhaltern -
116 * nur %' wird später zu ' so können auch direkt Funktionen auf einzelne Platzhalter übergeben werden
117 * @param Array $options Enthält Informationen zum Tag und für einzelne Platzhalter Funktionen 'Platzhalter' => Funktion/Methode
118 */
119 public function add_Tag($name, $bbcode, $htmlcode, $options = array()) {
120 $placeholders = array();
121 $place_holders = array();
122 if (count($options) > 0 && !$this->is_valid_function_array($options))
123 throw new Exception (__FILE__."; Zeile ".__LINE__." : Fehler in Funktionsarray für Tag "".$name."": ".print_r($options, true));
124
125 $pattern = $this->prepare_Pattern($bbcode, (isset($options['modifier'])) ? $options['modifier'] : 'isUe');
126 $search = array_flip($this->tags['search']);
127
128 if (in_array($pattern, $this->tags['search']) && $search[$pattern] != $name) {
129 throw new Exception (__FILE__."; Zeile ".__LINE__." : Fehler bei Erstellen von BB-Tag "".$name."": "".$search[$pattern]."" hat gleiches BBCode-Pattern");
130 }
131
132 if ($name == 'erde') {
133 throw new Exception (__FILE__."; Zeile ".__LINE__." : Fehler bei Erstellen von BB-Tag: Name 'erde' ist reserviert!");
134 }
135
136 preg_match_all("/%[a-z]/", $bbcode, $place_holders);
137 foreach ($place_holders[0] as $plc) {
138 $placeholders[$plc] = (isset($options[$plc])) ? $options[$plc] : null;
139 }
140
141 $html_array = $this->prepare_html_Output($htmlcode, $placeholders);
142
143 $this->tags['search'][$name] = $pattern;
144 $this->tags['replace'][$name] = $html_array[0];
145 $this->tags['plc'][$name] = $html_array[1];
146 $this->tags['allowed_in'][$name] = (isset($options['allowed_in'])) ? explode(';', $options['allowed_in']) : array();
147 $this->tags['allowed_within'][$name] = (isset($options['allowed_within'])) ? explode(';', $options['allowed_within']) : array();
148 }
149
150
151
152 /**
153 * core_util_BBParser::find_first_occurent($string, $search)
154 * Testet einen String auf mehrere reguläre Ausdrücke und gibt den zurück, der als erster greift
155 *
156 * @param String $string zu untersuchender String
157 * @param Array $search Array mit Regulären Ausdrücken
158 */
159 private function find_first_occurent($string, $search) {
160 $found = array();
161 $first = array('ID' => null, 'StrPos' => null, 'Str' => array(null, null, null));
162
163 foreach ($search as $id => $pattern) {
164 preg_match($pattern, $string, $found);
165 if (count($found) > 0) {
166 $strpos = strpos($string, $found[0]);
167 if (!isset($first['StrPos']) || $strpos < $first['StrPos']) {
168 $split = explode($found[0], $string, 2);
169
170 if (count($split) == 1) {
171 $split[0] = "";
172 $split[1] = "";
173 }
174 elseif (count($split) == 1) {
175 if ($strpos == 0) {
176 $split[1] = $split[0];
177 $split[0] = "";
178 }
179 else {
180 $split[1] = "";
181 }
182 }
183
184
185 $first['ID'] = $id;
186 $first['StrPos'] = $strpos;
187 $first['Str'][0] = $split[0];
188 $first['Str'][1] = $found[0];
189 $first['Str'][2] = $split[1];
190 if ($strpos === 0) break;
191 }
192 }
193 }
194
195 return $first;
196 }
197
198 /*
199 private function get_allowed_pattern(&$IDs) {
200 $search = array();
201 $cache = 'erde';
202 $cached_IDs = $IDs;
203 $cached2_IDs = array();
204 if (count($IDs) == 0) {
205 return $this->tags['search'];
206 }
207 else {
208 echo "\n\n\n";
209 foreach ($IDs as $index => $id) {
210 if (count($this->tags['allowed_within'][$IDs[$index]]) == 0 || in_array($cache, $this->tags['allowed_within'][$IDs[$index]])) {
211
212 $cached2_IDs = $cached_IDs;
213 print_r($cached_IDs);
214 foreach($cached_IDs as $index2 => $cached_id) {
215 if (!in_array($cached_id, $this->tags['allowed_in'][$IDs[$index]])) {
216 unset($cached2_IDs[$index2]);
217 }
218 }
219
220 $cached_IDs = $cached2_IDs;
221 $cache = $id;
222 }
223 else {
224 unset($cached_IDs[$index]);
225 }
226 }
227 $IDs = $cached_IDs;
228 foreach ($IDs as $id) {
229 $search[$id] = $this->tags['search'][$id];
230 }
231 var_dump($search);
232 return $search;
233 }
234 }
235 */
236
237 private function get_allowed_pattern($IDs) {
238 $search = array();
239 if (count($IDs) == 0) {
240 $search = $this->tags['search'];
241 }
242 else {
243 if (count($this->tags['allowed_in'][$IDs[0]]) == 0) {
244 $search = $this->tags['search'];
245 }
246 else {
247 foreach($this->tags['allowed_in'][$IDs[0]] as $pattern) {
248 $search[$pattern] = $this->tags['search'][$pattern];
249 }
250 }
251 }
252
253 $cache_search = $search;
254 foreach ($cache_search as $id => $pattern) {
255 if (!count($this->tags['allowed_within'][$id]) == 0 && !in_array((isset($IDs[0])) ? $IDs[0] : 'erde', $this->tags['allowed_within'][$id])) {
256 unset($search[$id]);
257 }
258 }
259 return $search;
260 }
261
262 /**
263 * core_util_BBParser::parse_rek($string, $name = null)
264 * ominöse Funktion, die rekursiv einen String parst. ^^
265 *
266 * @param String $string zu parsender String
267 * @param String $name ID des Strings
268 */
269 private function parse_rek($string, $IDs = array()) {
270 if (strlen(trim($string)) == 0) {
271 return $string;
272 }
273
274 $search = array();
275 $first = array();
276
277 //$strpos = 0;
278 $split = array();
279
280 //var_dump($string);
281 $search = $this->get_allowed_pattern($IDs);
282
283 $first = $this->find_first_occurent($string, $search);
284 if (strlen($first['Str'][1]) > 0) {
285 $inner_strings = array();
286
287 preg_match_all($this->tags['search'][$first['ID']], $first['Str'][1], $inner_strings);
288 array_shift($inner_strings);
289 array_unshift($IDs, $first['ID']);
290
291 foreach ($inner_strings as $index => $plc) {
292 if ($this->tags['plc'][$first['ID']][$index] != "%s") {
293 $first['Str'][1] = str_replace($plc[0], $this->parse_rek($inner_strings[$index][0], $IDs), $first['Str'][1]);
294 }
295 else {
296 str_replace($plc[$index], $inner_strings[$index][0], $first['Str'][1]);
297 }
298 }
299
300 $first['Str'][2] = $this->parse_rek($first['Str'][2]);
301 $first['Str'][1] = preg_replace(str_replace("/isUe", "/ise", $this->tags['search'][$first['ID']]), $this->tags['replace'][$first['ID']], $first['Str'][1]);
302 return $first['Str'][0].$first['Str'][1].$first['Str'][2];
303 }
304 else {
305 return $string;
306 }
307 }
308
309
310
311 /**
312 * core_util_BBParser::parse($code)
313 * Parst übergebenen Code nach den vorher definierten Tags
314 *
315 * @param String $code zu parsender Code
316 */
317 public function parse($code) {
318 //print_r($this->tags);
319 //return preg_replace($this->tags['search'], $this->tags['replace'], $code);
320 return $this->parse_rek($code);
321 }
322 }
323 ?>.
Datei: Test.php:
<?
function __autoload($classname) {
global $config;
$classname = str_replace('_', '/', $classname);
$require = require_once('src/' . $classname . '.php');
if (!$require) echo 'File '.dirname($_SERVER['SCRIPT_FILENAME']).'/src/' . $classname . '.php not found!';
}
function highlight($str) {
$rows = array();
$str = highlight_string($str, true);
$str_array = explode("<br />", $str);
$i = 1;
foreach ($str_array as $row) {
$rows[] = '<font color="#808080">'.$i."</font>\t".$row;
$i++;
}
$str = implode("<br />", $rows);
return $str;
}
$fp = fopen(dirname($_SERVER['SCRIPT_FILENAME']).'/src/core/util/BBParser.php', "r");
$string = fread($fp, filesize(dirname($_SERVER['SCRIPT_FILENAME']).'/src/core/util/BBParser.php'));
fclose($fp);
echo '<html><body>';
try {
$parser = new core_util_BBParser(); // )
$parser->add_Tag('php', '[php]%s[/php]', '<div class="php">%\'.highlight(str_replace(%\'\"%\', %\'"%\', %\'.%s.%\')).%\'</div>');
//$parser->add_Tag('php', '[php]%s[/php]', '<div class="php">%s</div>', array('%s' => 'highlight'));
$parser->add_Tag('php2', '[php2]%s[/php2]', '<div class="php2">%s</div>');
echo 'geparster Text:<br />';
echo $parser->parse('[php]'.$string.'[/php]');
echo '<br /><br /><br /><br />Datei: Test.php:<br />';
highlight_file(__FILE__);
echo '<br /><br /><br /><br />Datei: BBParser.php:<br />';
highlight_file(dirname($_SERVER['SCRIPT_FILENAME']).'/src/core/util/BBParser.php');
echo '<br /><br /><br /><br />Text normal geparst<br />';
echo highlight($string);
}
catch (Exception $e) {
echo 'Error: '.$e->getMessage();
}
echo '</body></html>';
?>
Datei: BBParser.php:
<?php
/**
* BBParser
* parst Code auf konfigurierbare BBCode-Tags
*
* @author Johannes Schlichenmaier
* @version 01.03.2006
* @package core_util
*/
class core_util_BBParser {
private $tags = array('search' => array(), 'replace' => array(), 'plc' => array(), 'allowed_in' => array(), 'allowed_within' => array());
/**
* core_util_BBParser::construct($custom = false)
* Erstellt auf Wunsch häufige BBCode-Tags automatisch. Wenn nicht erwünscht, einfach mit "true" als Parameter aufrufen.
*
* @param boolean $custom Wenn "true" gesetzt, werden b, i , u, und zwei Varianten von Links (link - [url=...]...[/url] -
* und url - [url]...[/url]- ) nicht erstellt.
*/
public function __construct($custom = false) {
if ($custom === false) {
$this->add_Tag('b', '[b]%b[/b]', '<b>%b</b>');
$this->add_Tag('i', '[i]%i[/i]', '<i>%i</i>');
$this->add_Tag('u', '[u]%u[/u]', '<u>%u</u>');
$this->add_Tag('link', '[url=%s]%l[/url]', '<a href="%s">%l</a>');
$this->add_Tag('url', '[url]%s[/url]', '<a href="%s">%s</a>');
}
}
/**
* core_util_BBParser::prepare_Pattern($string)
* wandelt einen BBCode zu einem Regulären Ausdruck um
*
* @param String $string umzuwandelnder String
*/
private function prepare_Pattern($string, $modifiers) {
$string = addcslashes($string,'\'\\/,^$.[]|()?*+{}');
$string = preg_replace("/%[a-z]/", "(.*)", $string);
$string = '/'.$string.'/'.$modifiers;
return $string;
}
/**
* core_util_BBParser::prepare_html_Output($string, $placeholders)
* bereitet den übergebenen HTML-Code mit den Platzhaltern für die Verwendung in preg_replace vor
*
* @param String $string umzuwandelnder HTML-Code
* @param Array $placeholders Array mit in dem BBCode gefundenen Platzhaltern in der Reihenfolge ihres Auftretens
*/
private function prepare_html_Output($string, $placeholders) {
$i = 0;
$return = array("", array());
$return[0] = str_replace(array("'", "%\'"), array("\'", "'"), $string);
$return[0] = "'".$return[0]."'";
foreach ($placeholders as $index => $plc) {
$return[1][] = $index;
if ($plc !== null) {
$return[0] = str_replace($index, "'.".$plc."(str_replace('\\\"', '\"','\$".($i+1)."')).'", $return[0]);
}
else {
$return[0] = str_replace($index, "'.str_replace('\\\"', '\"', '\$".($i+1)."').'", $return[0]);
}
$i++;
}
return $return;
}
/**
* core_util_BBParser::is_valid_function_array(&$name)
* Überprüft, ob ein übergebenes Array mit Platzhaltern gültige Funktionen/Methoden enthält
*
* @param &Array $name Array mit Platzhaltern (und zusätzlichen Informationen)
*/
private function is_valid_function_array(&$name) {
$all_valid = true;
foreach ($name as $plc => $function) {
$valid = true;
if (preg_match("/^%[a-z]/", $plc)) {
if (stristr($function, '$this->') !== false) {
$function_array = explode('->', $function);
if (!is_callable(array($this, $function_array[1]))) $valid = false;
}
elseif (strstr($function, '::') !== false) {
$function_array = explode('::', $function);
if (!is_callable(array("$function_array[0]", $function_array[1]))) $valid = false;
}
else {
if (!function_exists($function)) $valid = false;
}
if (!$valid) {
$all_valid = false;
$name[$plc] = $name[$plc].' - ERROR: method/function is not callable';
}
}
}
return $all_valid;
}
/**
* core_util_BBParser::add_Tag($name, $bbcode, $htmlcode, $options = array())
* Fügt einen weiteren BBCode-Tag zum Suchalgorithmus hinzu
*
* Platzhalter: ein % mit anschließendem a-z.
* Besondere Platzhalter: %s : Darin gefundene Strings werden nicht weiter geparst - NOCH NICHT IMPLEMENTIERT
* %' : Wird im preg_replace später zu einem unescapten ' . Nützlich, um einzelne Platzhalter direkt durch Funktionen oder Methoden zu schicken.
*
* @param String $name Identifier des neuen Tags
* @param String $bbcode BBCode mit Platzhaltern
* @param String $htmlcode HTML-Code mit Platzhaltern -
* nur %' wird später zu ' so können auch direkt Funktionen auf einzelne Platzhalter übergeben werden
* @param Array $options Enthält Informationen zum Tag und für einzelne Platzhalter Funktionen 'Platzhalter' => Funktion/Methode
*/
public function add_Tag($name, $bbcode, $htmlcode, $options = array()) {
$placeholders = array();
$place_holders = array();
if (count($options) > 0 && !$this->is_valid_function_array($options))
throw new Exception (__FILE__."; Zeile ".__LINE__." : Fehler in Funktionsarray für Tag \"".$name."\": ".print_r($options, true));
$pattern = $this->prepare_Pattern($bbcode, (isset($options['modifier'])) ? $options['modifier'] : 'isUe');
$search = array_flip($this->tags['search']);
if (in_array($pattern, $this->tags['search']) && $search[$pattern] != $name) {
throw new Exception (__FILE__."; Zeile ".__LINE__." : Fehler bei Erstellen von BB-Tag \"".$name."\": \"".$search[$pattern]."\" hat gleiches BBCode-Pattern");
}
if ($name == 'erde') {
throw new Exception (__FILE__."; Zeile ".__LINE__." : Fehler bei Erstellen von BB-Tag: Name 'erde' ist reserviert!");
}
preg_match_all("/%[a-z]/", $bbcode, <