Src2Textarea

Src2Textarea-Tutorial von Daniel Schwamm (09.03.2009)

Inhalt

1. Prolog

Dieses Tutorial beschreibt den Werdegang eines Projektes, welches - ganz ehrenrührig - Wahrheit verkünden will. Nämlich den Sourcecode einer Webseite so anzuzeigen, wie er ist.

Aufgrund ungünstiger Umstände in Form von HTML-Syntax, auf die man keinen Einfluss hat, muss dazu aber die Wahrheit gefälscht werden.

Da nun aber gefälschte Wahrheit keine Wahrheit mehr ist, muss die Fälschung ihrerseits gefälscht werden, jetzt aber wieder zur Wahrheit hin.

Die Fälschung der Fälschung bewirkt aber wiederum eine Fälschung derjenigen Wahrheit, die die Fälschung der Fälschung vornimmt, ist also ihrerseits nicht Wahrheit, womit das Ganze einmal mehr zwangsläufig zur Fälschung wird ...

Muss man also alle Hoffnung auf Wahrheit fahren lassen, so wie Unwahrheit zur Wiedergabe verwendet werden muss?

Nein, wie die folgende Dokumentation hoffentlich zu belegen weiss ...

2. Motivation

Die meisten meiner Talente sind ... nun ja, eher schwach ausgeprägt. Allerdings beherrsche ich ein Gebiet sicherlich besser als der bundesdeutsche Durchschnitt: Programmieren!

Daher dachte ich, es wäre eine nette Idee, den Leuten, die sich auf meine Homepage verirren, gleich einen Ausschnitt von dem aufzudrängen, womit ich mich am liebsten beschäftige, nämlich den oftmals kryptisch anmutenden Sourcecode von Computer-Programmen.

Und ein Beispiel, welches sich dazu als eine Art intellektueller Gag anbot, war der PHP-, HTML- und JavaScript-Source eben derjenigen Seite, auf der sich der Betrachter gerade selbst befand.

Die Startseite meiner Homepage sah daher von Ende 2007 bis Anfang 2009 in etwa so aus:

PHP - Src2Textarea - alte Homepage

Die alte Homepage: In der Textarea wird der Sourcecode der eigenen Seite angezeigt

Doch die "Sourcecode-Selbstanzeige" erwies sich als erstaunlich komplexes Problem, wie im Folgenden geschildert werden soll.

3. Versuche

3.1. Versuch I: Eigenen Sourcecode per PHP ausgeben

Zunächst muss man den PHP-Sourcecode der Webseite in irgendeiner Form von der Platte einladen. Dazu bietet sich der PHP-Befehl "file_get_contents()" an:

00001
00002
00003
00004
<?PHP
$fn
=__FILE__;
$src=file_get_contents($fn);
?>

Es wird hier einfach der Dateiname "$fn" übergeben und man erhält einen String "$src" zurück, der den kompletten Dateiinhalt speichert. Die Variable "__FILE__" ist in PHP eingebaut und enthält stets den Dateipfad des aufgerufenen Scripts.

Man könnte nun auf den naheliegenden Gedanken kommen, den String "$src" unmittelbar per "echo"-Kommando auszugeben, eingerahmt in die üblichen HTML-Tags einer gültigen Webseite, also z.B. auf diese Weise:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 
  'http://www.w3.org/TR/html4/loose.dtd'>
<html>
<head>
<META NAME='ROBOTS' CONTENT='INDEX, FOLLOW, ARCHIVE'>
<META HTTP-EQUIV='Content-Type' CONTENT='text/html; 
  charset=windows-1252'>
<meta name='author' content='Daniel Schwamm'>
<meta name='Description' content='Scr2Textarea - Tutorial 1: 
  Quellcode der eigenen PHP-Seite mit "echo" ausgeben'>
<meta name='Keywords' content='software, tutorial, php, src2textarea, echo'>
<link rel='canonical' href='http://www.henrys.de/daniel/index.php?
  cmd=software_php_src2textarea_script-echo-src.php'>
<title>[DAN] • Software - PHP - Scr2Textarea - Tutorial 1</title>
</head>

<?PHP

$fn
=__FILE__;
$src=file_get_contents($fn);
$fn=substr($fn,strpos($fn,"script"),strlen($fn));

echo 
"
<body>

<h1>Scr2Textarea - Tutorial 1</h1>
<h2>Quellcode der eigenen PHP-Seite mit 'echo' ausgeben</h2>

<b>Aktuelle Datei:</b> 
$fn
<hr>
$src
<hr>

</body>
</html>
"
;

?>

Doch seht selbst, was dabei herauskommt: "Script-Echo-Src.php", der erste Versuch

Verflixt! Man sieht tatsächlich genau das, was wir eigentlich anzeigen lassen wollten, gerade nicht! Der Webseiten-Source ist ausgeblendet. Holt man sich jedoch mit dem (IE-)Browser (über "Quelltext anzeigen") den Sourcecode (in Notepad), erkennt man, dass der oben gezeigte PHP-Script-Text durchaus vorhanden ist.

Allerdings ist er in das PHP-Start-Tag ("<?PHP") und das PHP-End-Tag ("?>") eingekapselt. Und da der Browser mit diesen Tags nichts anfangen kann, ignoriert er definitionsgemäss einfach alles, was sich dazwischen befindet.

3.2. Versuch II: Einsatz einer Textarea

Okay, in Versuch I haben wir gelernt, dass direkt ausgegebener PHP-Source auf der Webseite nicht erscheint, weil der Browser die PHP-Start- und -End-Tags als unbekannte Tags "interpretiert" und daher nicht weiter verarbeitet.

Um dies zu umgehen, kann die in HTML eingebaute "Textarea" zum Einsatz kommen. Schriftsätze, die darin eingebettet sind, werden nämlich normalerweise 1:1 auf dem Bildschirm wiedergegeben, ohne zuvor vom HTML-Parser "übersetzt" zu werden.

Ein passendes Programm dazu ist schnell getippt:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 
  'http://www.w3.org/TR/html4/loose.dtd'>
<html>
<head>
<META NAME='ROBOTS' CONTENT='INDEX, FOLLOW, ARCHIVE'>
<META HTTP-EQUIV='Content-Type' CONTENT='text/html; 
  charset=windows-1252'>
<meta name='author' content='Daniel Schwamm'>
<meta name='Description' content='Scr2Textarea - Tutorial 2: 
  Quellcode der eigenen PHP-Seite in "Textarea" ausgeben'>
<meta name='Keywords' content='software, tutorial, php, 
  src2textarea, textarea'>
<link rel='canonical' href='http://www.henrys.de/daniel/index.php?
  cmd=software_php_src2textarea_script-src-in-textarea.php'>
<title>[DAN] • Software - PHP - Scr2Textarea - Tutorial 2</title>
</head>

<body>

<h1>Scr2Textarea - Tutorial 2</h1>
<h2>Quellcode der eigenen PHP-Seite in 'Textarea' ausgeben</h2>

<?PHP
$fn
=__FILE__;
$src=file_get_contents($fn);
$fn=substr($fn,strpos($fn,"script"),strlen($fn));

echo 
"<b>Aktuelle Datei:</b> $fn<br><br>";

echo 
"<textarea cols='80' rows='20' wrap='off'>";
echo 
$src;
echo 
"</textarea>";
?>

</body>
</html>

Doch seht selbst, was dabei herauskommt: "Script-Src-in-Textarea.php", der zweite Versuch

Tja, das haut sicher besser hin als Versuch I. Man sieht tatsächlich fast den gesamten Sourcecode in der Textarea, allerdings fehlt der Schluss. Genauer: Direkt vor dem schliessenden Tag "</textare>" endet die Ausgabe - ab hier kommt der HTML-Parser offenbar durcheinander.

Also, was - zum Teufel - geht da schief?

Zur Fehlersuche muss sich gewissermassen in den HTML-Parser hineindenken. Der erkennt am Anfang "Aha, eben beginnt eine Textarea" und weiss "Ich muss nun alles ausgeben, bis ich das schliessende Tag '</textarea>' entdecke". Nun ist aber das gesuchte schliessende Tag wiederum Teil des auszugebenden Sourcecodes, muss also eigentlich mit ausgegeben werden, statt ein Zeichen davor den Output zu beenden, wie es die Syntax des HTML-Parsers aber zwingend vorschreibt.

Ein geradezu philosophisches Dilemma. Erinnert ein wenig an den Kerl, der auf einem Baum hockt und ausgerechnet an dem Ast herumsägt, auf dem er selbst sitzt ...

3.3. Versuch III: Textarea soll schliessendes Textarea-Tag ignorieren

In Versuch II haben wir gesehen, dass der HTML-Parser aufgrund der Ausgabe des schliessenden Textarea-Tags die Ausgabe früher beendet, als er eigentlich sollte.

Um dieses zu umgehen, verhindern wir in Versuch III - raffiniert, wie wir sind -, dass das besagte schliessende Textarea-Tag im Sourcecode auftaucht. Wir nutzen dazu die PHP-Funktion "str_replace()", mit deren Hilfe man bestimmte Textteile in einem String durch andere Inhalte ersetzen kann.

Indem wir das hier machen ...

00001
00002
00003
00004
<?PHP
$src
=file_get_contents($fn);
$src=str_replace("textarea","text_area",$src);
?>

... überschreiben wir das Auftauchen von "textarea" in "$src" durch "text_area". Findet der HTML-Parser nämlich dieses Dummy-Tag innerhalb einer Textarea, wird es wie normaler Text ausgegeben.

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 
  'http://www.w3.org/TR/html4/loose.dtd'>
<html>
<head>
<META NAME='ROBOTS' CONTENT='INDEX, FOLLOW, ARCHIVE'>
<META HTTP-EQUIV='Content-Type' CONTENT='text/html; 
  charset=windows-1252'>
<meta name='author' content='Daniel Schwamm'>
<meta name='Description' content='Scr2Textarea - Tutorial 3: 
  Quellcode der eigenen PHP-Seite in "Textarea" ausgeben ohne
 "Textarea"-Tags'>
<meta name='Keywords' content='software, tutorial, php, 
  src2textarea, echo'>
<link rel='canonical' href='http://www.henrys.de/daniel/index.php?
  cmd=software_php_src2textarea_script-src-in-textarea-ohne-tag.php'>
<title>[DAN] • Software - PHP - Scr2Textarea - Tutorial 3</title>
</head>

<body>

<h1>Scr2Textarea - Tutorial 3</h1>
<h2>Quellcode der eigenen PHP-Seite in 'Textarea' 
  ausgeben ohne 'Textarea'-Tags</h2>

Das "textarea"-Tag wird durch das ungültige "text_area"-Tag ersetzt!
<br><br>

<?PHP
$fn
=__FILE__;
$src=file_get_contents($fn);
$fn=substr($fn,strpos($fn,"script"),strlen($fn));

echo 
"<b>Aktuelle Datei:</b> $fn<br><br>";

$src=str_replace("textarea","text_area",$src);

echo 
"<textarea cols='80' rows='25' wrap='off'>";
echo 
$src;
echo 
"</textarea>";
?>

</body>
</html>

Doch seht selbst, was dabei herauskommt: "Script-Src-in-Textarea-ohne-Tag.php", der dritte Versuch

Ha! Das klappt. Der Source ist jetzt komplett in der Textarea enthalten.

Allerdings mit einem dickem Schönheitsfehler: Die Anzeige lügt nämlich - innerhalb der Textarea steht nun etwas von irgendwelchen "text_area"-Tags, die im echten Sourcecode der Seite nicht vorhanden sind. Würde jetzt jemand den Source aus der Textarea kopieren, um ihn für eigene Zwecke zu verwenden, könnte er in dieser "gefälschten" Form schlicht nicht funktionieren.

3.4. Versuch IV: Lügende Textarea wieder zur Wahrheit zwingen

Versuch III war weitgehend erfolgreich darin, den eigenen Sourcecode in einer Textarea anzuzeigen. Für die korrekte Ausgabe war es aber nötig, das "textarea"-Tag in "text_area" zu fälschen, sodass in Wirklichkeit doch nicht der originale Sourcecode wiedergegeben wird.

Es stellt sich also die Frage: Wie machen wir aus "text_area" nach der Ausgabe in der Textarea wieder "textarea"? Wie fälschen wir quasi die Fälschung durch eine erneute "Rückfälschung"?

Die Antwort: Per JavaScript (JS).

Schauen wir uns dazu folgenden Source an:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 
  'http://www.w3.org/TR/html4/loose.dtd'>
<html>
<head>
<META NAME='ROBOTS' CONTENT='INDEX, FOLLOW, ARCHIVE'>
<META HTTP-EQUIV='Content-Type' CONTENT='text/html; 
  charset=windows-1252'>
<meta name='author' content='Daniel Schwamm'>
<meta name='Description' content='Scr2Textarea - Tutorial 4: 
  Quellcode der eigenen PHP-Seite in "Textarea" ausgeben 
  ohne "Textarea"-Tags und mit JS-Korrektur'>
<meta name='Keywords' content='software, tutorial, php, src2textarea,
  echo, tag-filter, js-korrektur'>
<link rel='canonical' href='http://www.henrys.de/daniel/index.php?
  cmd=software_php_src2textarea_script-src-in-textarea-ohne-tag-js-korrektur.php'>
<title>[DAN] • Software - PHP - Scr2Textarea - Tutorial 4</title>
</head>

<body>

<h1>Scr2Textarea - Tutorial 4</h1>
<h2>Quellcode der eigenen PHP-Seite in 'Textarea' 
  ausgeben ohne 'Textarea'-Tags und mit JS-Korrektur</h2>

Per PHP "textarea" zu "text_area" ändern - und per Javascript wieder zurück
<br><br>

<?PHP
$fn
=__FILE__;
$src=file_get_contents($fn);
$fn=substr($fn,strpos($fn,"script"),strlen($fn));

echo 
"<b>Aktuelle Datei:</b> $fn<br><br>";

$src=str_replace("textarea","text_area",$src);

echo 
"<form name='frm'>";
echo 
"<textarea name='ta'cols='80' rows='25' wrap='off'>";
echo 
$src;
echo 
"</textarea>";
echo 
"</form>";
?>

<script language='javascript' type='text/javascript'>
alert("Vor der JS-Manipulation");
var ta_ar=document.frm.ta.value.split("\n"),s="";
for(r=0;r<ta_ar.length;r++){
  ss=ta_ar[r];
  ss=ss.replace("ext_area","extarea");
  s=s+ss+'\n';
};
document.frm.ta.value=s;
</script>

</body>
</html>

Zunächst kapseln wir die Textarea in eine HTML-Form namens "frm". Die Textarea erhält den Namen "ta". Diese Namensgebung ist nötig, damit wir auf die HTML-Objekte per JavaScript zugreifen können.

Nach der Ausgabe der Textarea beginnt der JavaScript-Teil. Über den "split"-Befehl transferieren wir den Inhalt der Textarea "ta" in das Zeilen-Array "ta_ar".

Danach durchlaufen wir das Zeilen-Array und ändern über das ""replace"-Kommando in jeder einzelnen Zeile das erste Auftauchen von "ext_area" in "extarea". Wohlgemerkt, wir ersetzen nicht "text_area" in "textarea", denn diese Zeichenfolge wäre durch den zuvor angewendeten PHP-Befehl "str_replace" ihrerseits manipuliert worden. Mit der Folge, dass auch der JS-Code fehlerhaft wiedergegeben würde, da dort ja sonst stünde, man würde "textarea" durch "text_area" ersetzen, also genau anders herum vorgehen ...

Brrr! Da verrenkt man sich echt das Hirn, wenn man zu lange darüber nachdenkt.

Leider haut unser Source aber auch so immer noch nicht ganz hin. Denn wir haben zwar erfolgreich verhindert, das PHP den JS-Source ändert, nicht jedoch, das JS sich selbst, also den eigenen JS-Code verfälscht!

Doch seht selbst, was dabei herauskommt: "Script-Src-in-Textarea-ohne-Tag-JS-Korrektur.php", der vierte Versuch

Wie man sieht, steht im JavaScript-Teil folgende Zeile:

00001
ss=ss.replace('extarea','extarea');

Korrekt ist aber:

00001
ss=ss.replace('ext_area','extarea');
 

Das dreckige JavaScript hat sich bei der Fälschung selbst gefälscht. Und zwar derart unglücklich, dass Fälschung und Original identisch sind, man nun also gar nicht mehr unterschieden kann, was was ist. Teufel aber auch, da sind wir doch glatt in eine Deadlock-Falle getappt.

4. Erfolg durch eingeschränkte Fälschung der ersten Fälschung des Originals

Unser Versuch IV, den eigenen Sourcecode in einer Textarea anzuzeigen, hat funktioniert. zumindest was den PHP-Teil betrifft. Dies haben wir durch nachträgliche Manipulation per JavaScript erreicht. Allerdings hört die JS-Fälschung nicht beim PHP-Source auf, sondern vergreift sich frecherweise auch am JS-Source, wodurch dieser nun seinerseits vom Original abweicht.

Im Prinzip ist damit schon angedeutet, wie das Dilemma aufgelöst werden kann: Der JS-Manipulations-Code darf überall wirken, nur halt nicht im JS-Script-Sourcecode selbst.

Der einfachste Weg, der mir einfiel, um das zu realisieren, war, mit Zeilennummern zu arbeiten. Da der JS-Code ganz am Schluss steht, haben wir es auch relativ leicht. Denn es muss dadurch nur dafür gesorgt werden, dass die JS-Manipulation ab der ersten JS-Zeile ausser Kraft gesetzt wird. Und diese Zeilennummer ist bei gegebenem Code eine Konstante (hier "52").

Schauen wir uns also den fertigen Source an:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 
  'http://www.w3.org/TR/html4/loose.dtd'>
<html>
<head>
<META NAME='ROBOTS' CONTENT='INDEX, FOLLOW, ARCHIVE'>
<META HTTP-EQUIV='Content-Type' CONTENT='text/html; 
  charset=windows-1252'>
<meta name='author' content='Daniel Schwamm'>
<meta name='Description' content='Scr2Textarea - Tutorial 5: 
  Quellcode der eigenen PHP-Seite in "Textarea" ausgeben 
  ohne "Textarea"-Tags und mit JS-Korrektur bis zu fixer Zeilennummer'>
<meta name='Keywords' content='software, tutorial, php, src2textarea,
  echo, tag-filter, js-korrektur, zeilennummer'>
<link rel='canonical' href='http://www.henrys.de/daniel/index.php?
  cmd=software_php_src2textarea_script.php'>
<title>[DAN] • Software - PHP - Scr2Textarea - Tutorial 5</title>
</head>

<?PHP

$fn
=__FILE__;
$src=file_get_contents($fn);

$src=str_replace("textarea","text_area",$src);

echo 
"
<body>
<center>

<h1>Scr2Textarea - Tutorial 5</h1>
<h2>Quellcode der eigenen PHP-Seite in 'Textarea' 
  ausgeben ohne 'Textarea'-Tags und mit JS-Korrektur
  bis zu fixer Zeilennummer</h2>
<hr>

<h1>Homepage von Daniel Schwamm</h1>

<form name='frm'>
<textarea name='ta' cols='80' rows='26' wrap='off'>
$src
</textarea>
</form>

<h2>Heimat des Dilettantismus</h2>
  
Zugriffe seit 11.12.98<br>
<img src='http://www.henrys.de/cgi-bin/bmc.exe?bmcdaniel.txt' 
 width='39' height='19' alt='Counter'>
</center>
"
;

?>

<script language='javascript' type='text/javascript'>
var ta_ar=document.frm.ta.value.split("\n"),s="";
for(r=0;r<ta_ar.length;r++){
  rs='0'+r; while(rs.length<3)rs='0'+rs;
  ss=ta_ar[r];if(r<52)ss=ss.replace("ext_area","extarea");
  s=s+rs+'| '+ss+'\n';
};
document.frm.ta.value=s;
</script>

</body>
</html>

Puh! Schwere Geburt, was? Für eine vermeintlich so simple Sache. Aber es funzt. Und alleine das zählt letztlich!

Doch seht selbst, was dabei herauskommt: "Script.php", der fünfte Versuch bringt endlich den Erfolg

"Src2Textarea" beweist uns also, dass Unwahrheit Unwahrheit produziert. Ist Wahrheit aber nicht direkt darstellbar, muss auf Lug und Betrug zurückgegriffen werden. Doch wer geschickt lügt, kann Fälschung durchaus wieder zur Wahrheit erheben - wie wir gerade gesehen haben.

Quod erat demonstrandum :-)