Geschrieben von i-spacke am 23.04.2006, 16:32

Ich schätze so ziemlich jeder kennt den BBCode [ php ][/ php ] (Leerzeichen nur zu Demonstrationszwecken), doch wie stellt man es eigentlich an, dass man den Code in eine so tolle Box mit Zeilennummerierung bekommt?
Ungefär so, wird unser Ergebnis später aussehen nur dass dann noch eine Zeilennummerierung sein wird.

<?php
echo "test"
?>

Das tolle ist, dass wir eine Funktion schreiben werden, die man einfach nur aufrufen muss und dann bekommt man so eine Box. :D

Ich habe zwar den Code mit Kommentaren versehen (was man so gut wie immer tun sollte), aber trotzdem werde ich euch (fast) alles erklären.

Außerdem gehe ich davon aus, dass ihr euch mit regex auskennt. Falls dies nicht der Fall sein sollte, dann könnt ihr euch hier darüber informieren oder einfach hinnehmen, dass der Code so funktioniert, wie ich ihn aufschreibe. ;)
http://www.php.net/manual/de/reference.pcre.pattern.syntax.php
http://www.php.net/manual/de/reference.pcre.pattern.modifiers.php

Genug der Vorrede. Das wichtigste, was wir eigentlich brauchen lifert PHP uns zum Glück von selbst. Die Funktion highlight_string() highlightet wie der Name schon sagt einen String, also eine Zeichenkette. Nähere Informationen findet ihr wie immer in der Online-Referenz. http://www.php.net/manual/de/function.highlight-string.php

Die Funktion gibt uns aber nur ungefähr <code><font color....bla bla bla</code> aus. Was wir also noch bewerkstelligen ist, dass wir irgendwie die einzelnen Zeilen nummerieren und das anshaulich in eine Tabelle formatieren. Außerdem sind die Tags <font> nicht mehr ganz so aktuell. Am besten wäre es, wenn wir daraus <span>-Tags machen könnten.

Nehmen wir mal an, man hat folgenden Code:
<?php
$text = '[php]<?php
echo "<a href=\"http://google.de\">google</a>test";//test
?>[/php]';
$text = htmlentities($text);
?>

Wichtig ist an dieser Stelle wie eigentlich bei allen Texteingaben, die Funktion htmlentities(), welche HTML-Sonderzeichen umwandelt. Würde man die snicht tun, so könnte man über ein Forumar z.B. eine automatische Weiterleitung einfügen. Klingt nicht so toll oder? ;) Warum das zu beachten ist, werdet ihr gleich sehen.

Erstmal der Code von der Funktion, die highlight_string quasi ersetzen soll:

<?php
################################
# Funktion(en) zum Highlighten #
# von PHP-Code #
# (c)By Spacke #
################################
//Funktion zum highlighten des Textes
function highlight_php($code) {
//HTML-Zeichen wieder zurueckformen
$code = str_replace('&amp;lt;', '<', $code);
$code = str_replace('&amp;gt;', '>', $code);
$code = str_replace('&amp;quot;', '"', $code);
//highlighten
$code = highlight_string($code, true);
//Konvertierung der color-tags zu span-tags
$code = preg_replace('`<font color="(.*?)">`is', '<span style="color:\\1">', $code);
$code = preg_replace('`</font>`is', '</span>', $code);

return $code;//Rueckgabe
}
?>

Als erstes deklarieren wir eine funktion mit dem Namen highlight_php. Die Funktion erwarten einen Parameter, was bei uns später der Text bzw. Code sein wird. Die ersten drei Zeilen wandeln die Zeichen, die htmlentities schon umgewandelt hat, wieder zurück. Das ist deswegen erforderlich, da der Text ja später zwischen <code>-Tags ausgegeben wird. Bei <code> werden Dinge wie < nicht umgewandelt, deswegen muss das hier schon geschehen.
Danach findet das eigentliche Highlighten statt. Das ist ja nicht sonderlich spektakulär, nicht wahr?^^
Die nächsten zwei Zeilen wandeln einfach nur die <font color="farbe">-tags in <span style="color:farbe;">-Tags um. Letztendlich wird das ganze Zeug mit return zurückgegeben.
Theoretisch könnte ich jetzt hier schon fast aufhören, da eigentlich nur noch die Tabelle fehlt. :D

Dazu kommen wir mit diesem Code:

<?php
//Funktion zum Hinzufuegen der Zahlen am Rand
function Lines($string, $split="\n") {
//Zaehlen der Zeilen des Codes
$lines = substr_count($string, $split); //Zaehlen der "\n", also Zeilenumbrueche
$ln = ''; //Initialisierung der Variable
//Fuellen der Variable mit den Zeilennummern via For-Schleife
for($i = 0; $i <= $lines; $i++){
$ln .= ($i+1).":\n";
}
//Ausrechnen der Hoeher fuer den I-Frame-artigen Div-Container
$height = ceil(($lines + 1) * 16.5) + 27 + 20;
//Hinzufuegen des Tabellengeruests
$ln = '
<table align="center" style="width:98%; table-layout: fixed;">
<tr>
<td><div style="overflow: auto; height:'.$height.'px; width: 100%;">
<table cellpadding="4" cellspacing="1" style="width:100%" class="phpcode">
<tr>
<td class="phpcode_head" style="font-weight:bold;font-family: Verdana, Tahoma, Helvetica;font-size:10px;margin:0px;"colspan="2">PHP Code:</td>
</tr>
<tr>
<td class="phpcode_numbers" nowrap="nowrap" align="right"><pre style="padding0px;margin:0px;font-family:monospace, Courier, MS Courier New;">'.$ln.'</pre></td>
<td valign="top" class="phpcode_code" nowrap="nowrap" align="left" style="width:100%;font-family:monospace,Courier, MS Courier New;">[php]'.$string.'[/php]</td>
</tr>
</table>
</div></td>
</tr>
</table>';
$ln .= "\n"; //Zeilenumbruch, fuer die Formatierung im Quelltext

return $ln; //Rueckgabe
}
?>

Mit der Funktion substr_count($string, $split) wird gezählt, wie oft das zeichen $split in dem string $string vorkommt. Das ist Quasi die Anzahl der Zeilen - 1, da die erste Zeile nicht mitgezählt wird. Mit der For-Schleife, welche so oft durchlaufen wird, wie wirkliche Zeilen vorhanden sind, wird dann immer wieder die Variable $ln mit einer neuen Zeile und der Nummer erweitert. Damit man mit .= arbeiten kann, was so viel bedetet, dass es einfach hinten an die Variable rangehängt wird, muss man die Variable davor mit einem Startwert, der in diesem Fall nichts ist, initialisieren.

Danach wird die Höhe für den Div-Container, der quasi ein I-Frame ersetzen soll, ausgerechnet. Auf diese Rechnung bin ich durch schlichtes Probieren gekommen und es sieht letztendlich auch in jedem Browser ein bisschen anders aus, aber zumindest im IE sollte es sehr gut hinkommen. Die Funktion ceil() rundet einfach nur.

In den nächsten Zeilen werden die Zeilen quasi in ein Tabellengerüst eingelesen. Außerdem wird das hier : [ php ]'.$string.'[/ php ]
noch eingefügt. Warum das geschah, werdet ihr gleich sehen, aber so viel kann ich sagen. Der Text ist ja noch lange nicht gehighlightet. ;)
Zum Schluss wird noch ein Zeilenumbruch erzwungen, damit es im Quellcode ein bisschen schöner aussieht und das ganze Zeug wird zurückgegeben.

Nun sind wir schon fast fertig. Es fehlt nur noch eine Funktion, die [ php ] - BBCodes im überlieferten text sucht und den Code dann durch die Funktionen jagt. :)


<?php
//Das eigentliche Parsen des uebergebenen Textes
function parse_php($text){
//Hinzufuegen der Zahlen
$text = preg_replace('`\[php\](.*?)\[/php\]`ies',"Lines('\\1')",$text);
//Highlighten und gleichzeitige Rueckgabe des Textes
return preg_replace('`\[php\](.*?)\[/php\]`ies',"highlight_php('\\1')",$text);
}
?>

Diese Funktion sucht zu erst im Text Stellen, die mit dem BBCode markiert sind und überliefert den Code an die Funktion, welche die Zeilennummerierung erstellt. Die BBCodes werden mit dem Rückgabewert der Funktion ersetzt. Nun wird auch klar, warum wir [ php ]'.$string.'[/ php ] noch eingesetzt haben. Schließlich muss der text da zwischen ja noch gehighlightet werden und ohne die BBCodes kann man ja nicht wissen, was ersetzt werden soll.
Die nächste Zeile ersetzt halt nun [php]'.$string.'[/php] mit dem gehightlighteten Code. Gleichzeitig geschieht die Rückgabe.

Das War auch schon. Nun zeige ich euch nur noch, wie ihr das ganze nun anwenden könnt:

<?php
$text = '[php]<?php
echo "<a href=\"http://google.de\">google</a>test";//test
?>[/php]';
$text = htmlentities($text);

echo parse_php($text);
?>

Einfach nur den Text an die Funktion parse_php übermitteln und schon habt ihr euren gehighlighteten Code. =)

Hier nochmal der ganze Code und dann noch ein CSS-Vorschlag:

<?php
################################
# Funktion(en) zum Highlighten #
# von PHP-Code #
# (c)By Spacke #
################################
//Funktion zum highlighten des Textes
function highlight_php($code) {
//HTML-Zeichen wieder zurueckformen
$code = str_replace('&amp;lt;', '<', $code);
$code = str_replace('&amp;gt;', '>', $code);
$code = str_replace('&amp;quot;', '"', $code);
//highlighten
$code = highlight_string($code, true);
//Konvertierung der color-tags zu span-tags
$code = preg_replace('`<font color="(.*?)">`is', '<span style="color:\\1">', $code);
$code = preg_replace('`</font>`is', '</span>', $code);

return $code;//Rueckgabe
}
//Funktion zum Hinzufuegen der Zahlen am Rand
function Lines($string, $split="\n") {
//Zaehlen der Zeilen des Codes
$lines = substr_count($string, $split); //Zaehlen der "\n", also Zeilenumbrueche
$ln = ''; //Initialisierung der Variable
//Fuellen der Variable mit den Zeilennummern via For-Schleife
for($i = 0; $i <= $lines; $i++){
$ln .= ($i+1).":\n";
}
//Ausrechnen der Hoeher fuer den I-Frame-artigen Div-Container
$height = ceil(($lines + 1) * 16.5) + 27 + 20;
//Hinzufuegen des Tabellengeruests
$ln = '
<table align="center" style="width:98%; table-layout: fixed;">
<tr>
<td><div style="overflow: auto; height:'.$height.'px; width: 100%;">
<table cellpadding="4" cellspacing="1" style="width:100%" class="phpcode">
<tr>
<td class="phpcode_head" style="font-weight:bold;font-family: Verdana, Tahoma, Helvetica;font-size:10px;margin:0px;"colspan="2">PHP Code:</td>
</tr>
<tr>
<td class="phpcode_numbers" nowrap="nowrap" align="right"><pre style="padding0px;margin:0px;font-family:monospace, Courier, MS Courier New;">'.$ln.'</pre></td>
<td valign="top" class="phpcode_code" nowrap="nowrap" align="left" style="width:100%;font-family:monospace,Courier, MS Courier New;">[php]'.$string.'[/php]</td>
</tr>
</table>
</div></td>
</tr>
</table>';
$ln .= "\n"; //Zeilenumbruch, fuer die Formatierung im Quelltext

return $ln; //Rueckgabe
}

//Das eigentliche Parsen des uebergebenen Textes
function parse_php($text){
//Hinzufuegen der Zahlen
$text = preg_replace('`\[php\](.*?)\[/php\]`ies',"Lines('\\1')",$text);
//Highlighten und gleichzeitige Rueckgabe des Textes
return preg_replace('`\[php\](.*?)\[/php\]`ies',"highlight_php('\\1')",$text);
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Test</title>
<style type="text/css">
.phpcode{
background-color: #000000;
}

.phpcode_head{
color:#dddddd;
background-color:#666666;
}

.phpcode_numbers{
background-color:#ffffff;
}

.phpcode_code{
background-color:#ffffff;
}

</style>
</head>
<body>
<?php
echo parse_php(htmlentities('
[php]<?php
echo "<a href=\"http://google.de\">google</a>test";//test
?>[/php]'));
?>
</body>
</html>

Dieser Code sieht dann so aus: http://i-spacke.milten.lima-city.de/tutorial_highlight_php.php

Ich hoffe ihr könnt diese Funktionen irgendwann benutzen. Ich selbst benutze sie in einer anderen Weise (Ich benutze verschiedene Klassen mit verschiedenen Parsern, aber das ist OOP und schon etwas fortgeschrittene Programmierung ;) ). Für kleinere Projekte reicht das hier allemal. Selbst für größere Projekte funktioniert es sehr gut. Per CSS hat man eigentlich alle Formatierungsmöglichkeiten.

Solltet ihr irgendwelche Fragen haben, dann schickt doch einfach eine PN.
mfg Spacke

P.s: Danke auch noch mal an Lucas, der meine nervigen Fragen ausgehalten und tweilweise beantwortet hat *g*. ;) (http://cycase.de | http://prycase.de)

Bewertung Anzahl
6
97,3 %
36 Bewertungen
5
2,7 %
1 Bewertungen