Web-Interface based Mail-Cleint




0: Also, ich bin bisher so weit gekommen:
1:
2: <?php
3: error_reporting(E_ALL);
4:
5: echo "<h2>TCP/IP-Verbindung</h2>\n";
6:
7: /* Den Port für den WWW-Dienst ermitteln. */
8: $service_port = getservbyname('smtp', 'tcp');
9:
10: /* Die IP-Adresse des Zielrechners ermitteln. */
11: $address = gethostbyname('127.0.0.1');
12:
13: /* Einen TCP/IP-Socket erzeugen. */
14: $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
15: if ($socket === false) {
16: echo "socket_create() fehlgeschlagen: Grund: " . socket_strerror(socket_last_error()) . "\n";
17: } else {
18: echo "OK.\n";
19: }
20:
21: echo "Versuche, zu '$address' auf Port '$service_port' zu verbinden ...";
22: $result = socket_connect($socket, $address, $service_port);
23: if ($result === false) {
24: echo "socket_connect() fehlgeschlagen.\nGrund: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
25: } else {
26: echo "OK.\n";
27: }
28:
29: $in = "HELO mail.talkortell.de\n";
30: $in .= "AUTH LOGIN\n";
31: $in .= base64_encode ("username");
32: $in .= "\n";
33: $in .= base64_encode ("passwort");
34: $in .= "\n";
35: $in .= "QUIT\n";
36: $out = '';
37:
38: echo "HTTP HEAD request senden ...";
39: socket_write($socket, $in, strlen($in));
40: echo "OK.\n";
41:
42: echo "Serverantwort lesen:\n\n";
43: while ($out = socket_read($socket, 2048)) {
44: echo $out;
45: }
46:
47: echo "Socket schließen ...";
48: socket_close($socket);
49: echo "OK.\n\n";
50: ?>








0: <?php
1: error_reporting(E_ALL);
2:
3: echo "<h2>TCP/IP-Verbindung</h2>\n";
4:
5: /* Den Port für den WWW-Dienst ermitteln. */
6: $service_port = getservbyname('smtp', 'tcp');
7:
8: /* Die IP-Adresse des Zielrechners ermitteln. */
9: $address = gethostbyname('127.0.0.1');
10:
11: /* Einen TCP/IP-Socket erzeugen. */
12: $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
13: if ($socket === false) {
14: echo "socket_create() fehlgeschlagen: Grund: " . socket_strerror(socket_last_error()) . "\n";
15: } else {
16: echo "OK.\n";
17: }
18:
19: echo "Versuche, zu '$address' auf Port '$service_port' zu verbinden ...";
20: $result = socket_connect($socket, $address, $service_port);
21: if ($result === false) {
22: echo "socket_connect() fehlgeschlagen.\nGrund: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
23: } else {
24: echo "OK.\n";
25: }
26:
27: $in = "HELO mail.talkortell.de\n";
28: $in .= "AUTH LOGIN\n";
29: $in .= base64_encode ("username");
30: $in .= "\n";
31: $in .= base64_encode ("passwort");
32: $in .= "\n";
33: $in .= "MAIL FROM: mailadressefrom\n";
34: $in .= "RCPT TO: mailadresseto\n";
35: $in .= "DATA\n";
36: $in .= "Text\n";
37: $in .= ".\n";
38: $in .= "QUIT\n";
39: $out = '';
40:
41: echo "HTTP HEAD request senden ...";
42: socket_write($socket, $in, strlen($in));
43: echo "OK.\n";
44:
45: echo "Serverantwort lesen:\n\n";
46: while ($out = socket_read($socket, 2048)) {
47: echo $out;
48: }
49:
50: echo "Socket schließen ...";
51: socket_close($socket);
52: echo "OK.\n\n";
53: ?>





Hähä, Hähä, Hähä, habe es hinbekommen!




0: <html>
1: <head>Dave Vajda's Webmail</head>
2: <body>
3: <form method="post">
4: <fieldset>
5: <legend>Webmail using postfix and telnet and PHP</legend>
6: <label for="Send a mail"> </label>
7: From: <input type="text" name="from" size="100"><br><br>
8: To: <input type="text" name="to" size="100"><br><br>
9: Subject: <input type="text" name="subject" size="100"><br><br>
10: Username: <input type="text" name="username" size="100"><br><br>
11: Password: <input type="text" name="password" size="100"><br><br>
12: Data: <input type="text" name="data" size="100" rows="40"><br><br>
13: <input type="Submit" value="Send Mail">
14: </fieldset>
15: </form>
16:
17: <?php
18: error_reporting(E_ALL);
19:
20: echo "<h2>Dave Vajda's Webmail</h2>\n";
21:
22: echo $_POST['from'];
23:
24: /* Den Port für den WWW-Dienst ermitteln. */
25: $service_port = getservbyname('smtp', 'tcp');
26:
27: /* Die IP-Adresse des Zielrechners ermitteln. */
28: $address = gethostbyname('192.168.178.28');
29:
30: /* Einen TCP/IP-Socket erzeugen. */
31: $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
32: if ($socket === false) {
33: echo "socket_create() fehlgeschlagen: Grund: " . socket_strerror(socket_last_error()) . "\n";
34: } else {
35: echo "OK.\n";
36: }
37:
38: echo "Versuche, zu '$address' auf Port '$service_port' zu verbinden ...";
39: $result = socket_connect($socket, $address, $service_port);
40: if ($result === false) {
41: echo "socket_connect() fehlgeschlagen.\nGrund: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
42: } else {
43: echo "OK.\n";
44: }
45:
46: $timestamp = time();
47: $date = date("d.m.Y",$timestamp);
48: $time = date("H:i",$timestamp);
49:
50: echo "Hallo!<br><br>";
51:
52: $in = "HELO mail.talkortell.de\n";
53: $in .= "AUTH LOGIN\n";
54: $in .= base64_encode ($_POST["username"]);
55: $in .= "\n";
56: $in .= base64_encode ($_POST["password"]);
57: $in .= "\n";
58: $in .= "MAIL FROM: " . $_POST["from"] . "\n";
59: $in .= "RCPT TO: " . $_POST["to"] . "\n";
60: $in .= "DATA\n";
61: $in .= "Subject: " . $_POST["subject"] . "\n";
62: $in .= "Date: " . $date . $time . "\n";
63: $in .= "from: " . $_POST["from"] . "\n\n";
64: $in .= $_POST["data"] . "\n";
65: $in .= ".\n";
66: $in .= "QUIT\n";
67: $out = '';
68:
69: socket_write($socket, $in, strlen($in));
70: echo "OK.\n";
71:
72: echo "Serverantwort lesen:\n\n";
73: while ($out = socket_read($socket, 2048)) {
74: echo $out;
75: }
76:
77: echo "Socket schließen ...";
78: socket_close($socket);
79: echo "OK.\n\n";
80: ?>
81: </body>
82: </html>





So, jetzt habe ich es endgültig hingekriegt:




0: <html>
1: <head>Dave Vajda's Webmail</head>
2: <body>
3: <form method="post">
4: <fieldset>
5: <legend>Webmail using postfix and telnet and PHP</legend>
6: <label for="Send a mail"> </label>
7: From: <input type="text" name="from" size="100"><br><br>
8: To: <input type="text" name="to" size="100"><br><br>
9: Subject: <input type="text" name="subject" size="100"><br><br>
10: Username: <input type="text" name="username" size="100"><br><br>
11: Password: <input type="password" name="password" size="100"><br><br>
12: Data: <input type="text" name="data" size="100" rows="40"><br><br>
13: <input type="Submit" value="Send Mail">
14: </fieldset>
15: </form>
16:
17: <?php
18: error_reporting(E_ALL);
19:
20: echo "<h2>Dave Vajda's Webmail</h2>\n";
21:
22: echo $_POST['from'];
23:
24: /* Den Port für den WWW-Dienst ermitteln. */
25: $service_port = getservbyname('smtp', 'tcp');
26:
27: /* Die IP-Adresse des Zielrechners ermitteln. */
28: $address = gethostbyname('192.168.178.28');
29:
30: /* Einen TCP/IP-Socket erzeugen. */
31: $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
32: if ($socket === false) {
33: echo "socket_create() fehlgeschlagen: Grund: " . socket_strerror(socket_last_error()) . "\n";
34: } else {
35: echo "OK.\n";
36: }
37:
38: echo "Versuche, zu '$address' auf Port '$service_port' zu verbinden ...";
39: $result = socket_connect($socket, $address, $service_port);
40: if ($result === false) {
41: echo "socket_connect() fehlgeschlagen.\nGrund: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
42: } else {
43: echo "OK.\n";
44: }
45:
46: $thedate = gmdate('D, d M Y H:i:s T');
47: echo $thedate;
48:
49: echo "Hallo!<br><br>";
50: echo time();
51:
52: $in = "HELO mail.talkortell.de\n";
53: $in .= "AUTH LOGIN\n";
54: $in .= base64_encode ($_POST["username"]);
55: $in .= "\n";
56: $in .= base64_encode ($_POST["password"]);
57: $in .= "\n";
58: $in .= "MAIL FROM: " . $_POST["from"] . "\n";
59: $in .= "RCPT TO: " . $_POST["to"] . "\n";
60: $in .= "DATA\n";
61: $in .= "From: " . $_POST["from"] . "\n";
62: $in .= "To: " . $_POST["to"]. "\n";
63: $in .= "Subject: " . $_POST["subject"] . "\n";
64: $in .= "Date: " . $thedate . "\n";
65: $in .= "Message-ID: <" . time() . "@talkortell.de>\n\n";
66: $in .= $_POST["data"] . "\n";
67: $in .= ".\n";
68: $in .= "QUIT\n";
69: $out = '';
70:
71: socket_write($socket, $in, strlen($in));
72: echo "OK.\n";
73:
74: echo "Serverantwort lesen:\n\n";
75: while ($out = socket_read($socket, 2048)) {
76: echo $out;
77: }
78:
79: echo "Socket schließen ...";
80: socket_close($socket);
81: echo "OK.\n\n";
82: ?>
83: </body>
84: </html>





Jetzt ist das Passwort als Passwort. Das Zeit und Datumsformat stimmt. Und außerdem stimmt die Message-ID. Ich habe das Format der Mail aus dem
https://tools.ietf.org/html/rfc5322
Also, der rfc5322 zur Beschreibung des Formats einer Mail. Und zwar habe ich hier ein ganz einfaches Format benutzt:

From: John Doe <jdoe@machine.example>
To: Mary Smith <mary@example.net>
Subject: Saying Hello
Date: Fri, 21 Nov 1997 09:55:06 -0600
Message-ID: <1234@local.machine.example>





Das geile an der Sache ist: Das ist jetzt Ultra-Geil und vor allem Ultra-Genial. Genialer geht es nicht! Weil: Dieses Webmail ist so sicher, wie postfix ist. Sicherer als postfix ist es nicht. Allerdings: Es ist noch sicherer! Warum? Ganz einfach: Wenn wir eine HTTPS-Verbindung aufbauen und trotzdem nur SMTP und nicht SMTPS auf dem postfix-Mailserver verwenden, dann wird über dieses Webmail über HTTPS das Passwort verschlüsselt übertragen. Aber: Der Mailserver befindet sich in diesem Fall auf jeden Fall auf dem Webserver. Und das Lustige ist: Die ganzen Telnet-Aktionen, die nun stattfinden finden nicht über das ganze Netz verteilt statt, sondern auf dem Server selber, zum Beispiel auf 192.168.178.28 oder gleich: 127.0.0.1 . Das heißt, was hier vom telnet zum Mailserver übetragen wird, ist gar nicht sichtbar - nach außen. Wenn nicht HTTPS verwenden, sondern nur HTTP. Wir die Sache nicht unsicherer. Denn: Das Passwort wird nur genauso wenig verschlüsselt übertragen, wie bei SMTP. Haben wir aber den Server postfix nicht anders eingerichtet, ist das nicht weniger sicherer, als per SMTP von unserem Mailclient. Wir haben aber kein Problem nicht, wir brauchen keine Sessions. Und Sessions mit PHP machen, ist in meinen Augen so eine Sache. Das ist es so oder so. Erstens ist das sehr komplex. Zweitens besteht aber immer das Problem: Zum Beispiel, wenn ich mit ID's arbeite, dann kann man das immer auslesen. Aber, wie doof muss das sein? Ich mache ein Webmail, jemand kommt rein. Das wäre nicht gut. Wenn ich ein Webmail mache - wenn ich das mache - dann muss das 100% sicher sein. Und, wenn ich mich nur auf die Sessions vom postfix mit telnet verlasse, ist das sicher. Es gibt noch einen Faktor: Ich weiß, was ich tue. Denn, man kann mir David Vajda, zwar etwas über Sessions erzählen, aber worüber man mir nichts erzählen kann, ist über SMTP- und IMAP-Protokolle, so wie dem Mail-Format. Das ist das Lustige: Ich weiß, was ich tue. Und, auch, wenn ich das Passwort dann eben neu eingebe. Das ist egal! Weil, ich weiß, was ich tue. Und es richtig. Und das ist der Unterschied. Es ist richtig. Und das Lustige ist: Ich benutze kein "mail" Command unter Linux oder nichts anderes. Nicht mal das telnet der Konsole benutze ich. Und das ist lustig. Weil hier, so wie ich das mache, weiß ich was ich mache, und das ist richtig!




Und, wenn man es so macht ist es noch richtiger.




0: <html>
1: <head>Dave Vajda's Webmail</head>
2: <body>
3: <form method="post">
4: <fieldset>
5: <legend>Webmail using postfix and telnet and PHP</legend>
6: <label for="Send a mail"> </label>
7: From: <input type="text" name="from" size="100"><br><br>
8: To: <input type="text" name="to" size="100"><br><br>
9: Subject: <input type="text" name="subject" size="100"><br><br>
10: Username: <input type="text" name="username" size="100"><br><br>
11: Password: <input type="password" name="password" size="100"><br><br>
12: Data: <textarea rows="40" cols="60" name="data">Hallo dies ist eine mail.talkortell.de Mail</textarea><br><br>
13: <input type="Submit" value="Send Mail">
14: </fieldset>
15: </form>
16:
17: <?php
18: error_reporting(E_ALL);
19:
20: echo "<h2>Dave Vajda's Webmail</h2>\n";
21:
22: echo $_POST['from'];
23:
24: /* Den Port für den WWW-Dienst ermitteln. */
25: $service_port = getservbyname('smtp', 'tcp');
26:
27: /* Die IP-Adresse des Zielrechners ermitteln. */
28: $address = gethostbyname('192.168.178.28');
29:
30: /* Einen TCP/IP-Socket erzeugen. */
31: $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
32: if ($socket === false) {
33: echo "socket_create() fehlgeschlagen: Grund: " . socket_strerror(socket_last_error()) . "\n";
34: } else {
35: echo "OK.\n";
36: }
37:
38: echo "Versuche, zu '$address' auf Port '$service_port' zu verbinden ...";
39: $result = socket_connect($socket, $address, $service_port);
40: if ($result === false) {
41: echo "socket_connect() fehlgeschlagen.\nGrund: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
42: } else {
43: echo "OK.\n";
44: }
45:
46: $thedate = gmdate('D, d M Y H:i:s T');
47: echo $thedate;
48:
49: echo "Hallo!<br><br>";
50: echo time();
51:
52: $in = "HELO mail.talkortell.de\n";
53: $in .= "AUTH LOGIN\n";
54: $in .= base64_encode ($_POST["username"]);
55: $in .= "\n";
56: $in .= base64_encode ($_POST["password"]);
57: $in .= "\n";
58: $in .= "MAIL FROM: " . $_POST["from"] . "\n";
59: $in .= "RCPT TO: " . $_POST["to"] . "\n";
60: $in .= "DATA\n";
61: $in .= "From: " . $_POST["from"] . "\n";
62: $in .= "To: " . $_POST["to"]. "\n";
63: $in .= "Subject: " . $_POST["subject"] . "\n";
64: $in .= "Date: " . $thedate . "\n";
65: $in .= "Message-ID: <" . time() . "@talkortell.de>\n\n";
66: $in .= $_POST["data"] . "\n";
67: $in .= ".\n";
68: $in .= "QUIT\n";
69: $out = '';
70:
71: socket_write($socket, $in, strlen($in));
72: echo "OK.\n";
73:
74: echo "Serverantwort lesen:\n\n";
75: while ($out = socket_read($socket, 2048)) {
76: echo $out;
77: }
78:
79: echo "Socket schließen ...";
80: socket_close($socket);
81: echo "OK.\n\n";
82: ?>
83: </body>
84: </html>





Die andere Richtung, mit IMAP, ist viel komplizierter. Viel, viel komplizierter. Weil wir müssen einerseits, die Mails auflisten. Und dazu alleine müssen wir in der Liste auf eine schlaue Art und Weise angeben, wie die Mails heißen. Dazu müssen wir aber die Liste auseinander nehmen. Das heißt, wir müssen hier in die Zeichenkette rein. Und nicht nur das: Es genügt einfach, wie bei IMAP an zu geben, OK, Nummer so und so. Wenn die überschritten wird und ich nicht mal, weiß, wie viele es gibt, ist das schon dumm. Aber nicht nur das: Um die Nummer zu erfahren, muss ich bereits Zeichenketten auseinander nehmen. Nichts desto trotz, das Problem mit dem Versenden von E-Mails habe ich bestens gelöst. Jetzt arbeite ich noch an den Strings, die in den PHP-Dingens sind. Da stehen noch Dinge, die da nicht hingehören, ins Benutzerinterface. Was aber auch so lustig ist, an der Sache, ich brauche jetzt gar nicht mich um Benutzerverwaltung zu kümmern. Nehmen wir mal, ich benutze eine Session von PHP. Ja, was ist dann? Gute Frage: Ganz einfach: Großer Mist. Ich muss die in einer Datenbank speichern. Und: Dann muss ich alle Mailaccounts, die so oder so schon im SASL drin sind, noch mal raus nehmen, in eine Datenbank rein - das ist doch schrecklich. Und hier: Und hier läuft nichts falsch. Das kann nicht schief laufen. Auf der einen Seite ist es mein Werk. Entschuldigung, das telnet kann ich selber schreiben. Das kann ich in C und PHP. Und das kann man so lernen. Und auf der ebene muss man das benutzen, das sind die TCP/IP-Schnittstellen in C oder PHP, das passt. Aber: Wenn man guckt: Von der Fehleranfälligeit, ist das postfix. Das ist nicht mehr und weniger als postfix. Und das 100% postfix. Und auch das SASL ist postfix. Und trotzdem ist es mein Werk!




So jetzt sieht das auch schon besser aus.









0: <html>
1: <head>Dave Vajda's Webmail</head>
2: <body>
3: <form method="post">
4: <fieldset>
5: <legend>Webmail using postfix and telnet and PHP</legend>
6: <label for="Send a mail"> </label>
7: <table>
8: <tr><td>From:</td><td> <input type="text" name="from" size="100"></td></tr>
9: <tr><td>To:</td><td> <input type="text" name="to" size="100"></td></tr>
10: <tr><td>Subject:</td><td> <input type="text" name="subject" size="100"></td></tr>
11: <tr><td>Username:</td><td> <input type="text" name="username" size="100"></td></tr>
12: <tr><td>Password:</td><td> <input type="password" name="password" size="100"></td></tr>
13: <tr><td></td><td> <textarea rows="40" cols="60" name="data">Hallo dies ist eine mail.talkortell.de Mail</textarea></td></tr>
14: </table>
15: <input type="Submit" value="Send Mail">
16: </fieldset>
17: </form>
18:
19: <?php
20: error_reporting(E_ALL);
21:
22: echo "<h2>Dave Vajda's Webmail</h2>\n";
23:
24: /* Den Port für den WWW-Dienst ermitteln. */
25: $service_port = getservbyname('smtp', 'tcp');
26:
27: /* Die IP-Adresse des Zielrechners ermitteln. */
28: $address = gethostbyname('192.168.178.28');
29:
30: /* Einen TCP/IP-Socket erzeugen. */
31: $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
32: if ($socket === false) {
33: echo "socket_create() fehlgeschlagen: Grund: " . socket_strerror(socket_last_error()) . "\n";
34: } else {
35: echo "OK.\n";
36: }
37:
38: echo "Versuche, zu '$address' auf Port '$service_port' zu verbinden ...";
39: $result = socket_connect($socket, $address, $service_port);
40: if ($result === false) {
41: echo "socket_connect() fehlgeschlagen.\nGrund: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
42: } else {
43: echo "OK.\n";
44: }
45:
46: echo time();
47:
48: $in = "HELO mail.talkortell.de\n";
49: $in .= "AUTH LOGIN\n";
50: $in .= base64_encode ($_POST["username"]);
51: $in .= "\n";
52: $in .= base64_encode ($_POST["password"]);
53: $in .= "\n";
54: $in .= "MAIL FROM: " . $_POST["from"] . "\n";
55: $in .= "RCPT TO: " . $_POST["to"] . "\n";
56: $in .= "DATA\n";
57: $in .= "From: " . $_POST["from"] . "\n";
58: $in .= "To: " . $_POST["to"]. "\n";
59: $in .= "Subject: " . $_POST["subject"] . "\n";
60: $in .= "Date: " . $thedate . "\n";
61: $in .= "Message-ID: <" . time() . "@talkortell.de>\n\n";
62: $in .= $_POST["data"] . "\n";
63: $in .= ".\n";
64: $in .= "QUIT\n";
65: $out = '';
66:
67: socket_write($socket, $in, strlen($in));
68: echo "OK.\n";
69:
70: echo "Serverantwort lesen:\n\n";
71: while ($out = socket_read($socket, 2048)) {
72: echo $out;
73: }
74:
75: echo "Socket schließen ...";
76: socket_close($socket);
77: echo "OK.\n\n";
78: ?>
79: </body>
80: </html>





Das wird jetzt in meine Homepage integriert. Und sobald jemand einen Mail-Account von mir hat, es geht.




Und, damit die Sache echt gut ist, bringe ich das Facebook-Banner von oben einfach, in diesem Web-Interface-Mail-Client unter.




So, ich habe es integriert:
http://www.talkortell.de/webinterfacemailclient.php





So, jetzt habe ich das richtig gemacht, so ist es auf meiner Homepage.







0: <html>
1: <head>Dave Vajda's Webinterfacemailclient</head>
2: <body>
3: <form method="post">
4: <fieldset>
5: <legend>Webinterfacemailclient using postfix and telnet and PHP</legend>
6: <label for="Send a mail"> </label>
7: <table>
8: <tr><td>From:</td><td> <input type="text" name="from" size="100"></td></tr>
9: <tr><td>To:</td><td> <input type="text" name="to" size="100"></td></tr>
10: <tr><td>Subject:</td><td> <input type="text" name="subject" size="100"></td></tr>
11: <tr><td>Username:</td><td> <input type="text" name="username" size="100"></td></tr>
12: <tr><td>Password:</td><td> <input type="password" name="password" size="100"></td></tr>
13: <tr><td></td><td> <textarea rows="40" cols="60" name="data">Hallo dies ist eine mail.talkortell.de Mail</textarea></td></tr>
14: </table>
15: <input type="Submit" value="Send Mail">
16: </fieldset>
17: </form>
18:
19: <?php
20: error_reporting(E_ALL);
21:
22: echo "<h2>Dave Vajda's Webinterfacemailclient</h2>\n";
23:
24: /* Den Port für den WWW-Dienst ermitteln. */
25: $service_port = getservbyname('smtp', 'tcp');
26:
27: /* Die IP-Adresse des Zielrechners ermitteln. */
28: $address = gethostbyname('192.168.178.28');
29:
30: /* Einen TCP/IP-Socket erzeugen. */
31: $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
32: if ($socket === false) {
33: echo "socket_create() fehlgeschlagen: Grund: " . socket_strerror(socket_last_error()) . "\n";
34: } else {
35: echo "OK.\n";
36: }
37:
38: echo "Versuche, zu '$address' auf Port '$service_port' zu verbinden ...";
39: $result = socket_connect($socket, $address, $service_port);
40: if ($result === false) {
41: echo "socket_connect() fehlgeschlagen.\nGrund: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
42: } else {
43: echo "OK.\n";
44: }
45:
46: $thedate = gmdate('D, d M Y H:i:s T');
47:
48: $in = "HELO mail.talkortell.de\n";
49: $in .= "AUTH LOGIN\n";
50: $in .= base64_encode ($_POST["username"]);
51: $in .= "\n";
52: $in .= base64_encode ($_POST["password"]);
53: $in .= "\n";
54: $in .= "MAIL FROM: " . $_POST["from"] . "\n";
55: $in .= "RCPT TO: " . $_POST["to"] . "\n";
56: $in .= "DATA\n";
57: $in .= "From: " . $_POST["from"] . "\n";
58: $in .= "To: " . $_POST["to"]. "\n";
59: $in .= "Subject: " . $_POST["subject"] . "\n";
60: $in .= "Date: " . $thedate . "\n";
61: $in .= "Message-ID: <" . time() . "@talkortell.de>\n\n";
62: $in .= $_POST["data"] . "\n";
63: $in .= ".\n";
64: $in .= "QUIT\n";
65: $out = '';
66:
67: socket_write($socket, $in, strlen($in));
68: echo "OK.\n";
69:
70: echo "Serverantwort lesen:\n\n";
71: while ($out = socket_read($socket, 2048)) {
72: echo $out;
73: }
74:
75: echo "Socket schließen ...";
76: socket_close($socket);
77: echo "OK.\n\n";
78: ?>
79: </body>
80: </html>







Wir müssen den Web-Interface-Mail-Client um etwas erweitern: Es muss nämlich erlaubt sein Anhänge zu verschicken. Dazu gehen wir wie folgt vor: Erstens (1.) wollen wir keinen Müll auf der Festplatte haben. Wenn ein User nämlich damit beginnt, eine Datei hoch zu laden, der nächste, die nächste, dann ist da nachher Müll. Außerdem kriegen wir Probleme mit den Dateiennamen. Sollten nämlich zwei den gleichen Dateinamen haben (2.) haben wir noch ein Problem: Hacker (!). Ein Hacker könnte nämlich eine ausführbare Datei als Anhang hochladen. Macht er das und sie bleibt auf der Platte, kann er sie ausführen. Just in diesem Moment, beginnt das Hacking. Er kann sie zwar nicht ausführen, weil sich ausführbare Dateien nicht einfach auf einem HTTP-Server ausführen lassen, aber, er kann noch ein PHP-Skript hochladen und damit die ausführbare Datei ausführen. Um das zu verhindern, wird die Datei direkt mit base64 umgewandelt und an die Mail angehängt. Danach wird sie gelöscht. Wird noch ein Anhang angehängt, beginnt das Spiel von vorne. Aber dabei werden die Anhänge nicht solange auf der Platte bleiben, solange die Mail bearbeitet wird. Sondern, das ist ein Schritt: Hochladen und direkt umwandeln, dann löschen. Das ist trotzdem auch problematisch. Denn der Akteuer könnte kein Mensch sein, sondern ein Roboter. Und dieser könnte die Zeit nutzen, in der, der Anhang mit base64 umgewandelt wird. Wenigstens für ein paar Ticks, pico oder nano Sekunden, ist die Datei auf der Festplatte. Mit geschickten Möglichkeiten des Computers könnte schon das genutzt werden. Darüber muss man nachdenken. Dann haben wir noch ein Problem: Der content-type. Generell soll der User in der Lage sein, jede Form von Anhang zu verschicken. Hier muss etwas am Mail-Format gearbeiett werden.

=>

Mime-Type: Content-Type: multipart/mixed;




Jetzt, meine Damen und Herren, wird die Sache erst lustig! Lucky Lucky Day! Hey Hey, Congratulations! Mein Webinterface ist lustig! Denn es tut mit meinem Server. Aber boah ey! Ist das ein Mist - that is awesome! Why? Für alle nicht zu 100% Kundigen; Es ist sicher - ja - so sicher. Und: Es ist von mir programmiert - ja. Und es benutzt postfix und eben: Keine Tricks. Aber, what a fuck! Es ist ein Mail-Client. Denken sie an den Mail-Client, den sie standardmäßig benutzen, wenn sie kein Web-Interface benutzen. Das ist das. Nur: Es ist ein Webinterface. Und trotzdem: Ein Client. Und: Das lustige ist: Es ist Mail - es benutzt IMAP. Also kein Scheiß. Es ist nicht irgendetwas: Mail-Client, das klingt harmlos - Webinterface - das ist klingt harmlos - sehr harmlos. Aber es benutzt IMAP - also ein Protokoll. Es ist also gar nicht auf so einer dummen Ebene. Aber: Ha ha! Fällt uns da nicht eine neue Marketing-Strategie ein: Genau: Ein Mail-Client beruhend auf einem Webinterface. Weil: Rein theoretisch können sie diesen Mail-Client beruhend auf Web, auf jeden Server benutzen, oder von wo sie PHP ausführen können. Aber: Es könnte einen anderen Mailserver nutzen. Sie können meinen benutzen und mit ein paar wenigen Handgriffen wird es trotzdem von einem anderen Webserver ausführt. Aber: Was wäre denn: Wenn man einen Webinterface schreibt, was standardmäßig einen Mailserver benutzt, meinen. Es ließen sich dabei aber eine Unmenge an anderen Mailservern verwenden, die in den Einstellungen eingeben werden. Die Frage ist nur, wie wir das machen? Wollen wir etwa jedes Mal die Adresse des fremden Mailservers eingeben? Und die Antwort lautet: "Nein". Das wollen wir nicht. Wir benutzen eine Datenbank - mit mySQL. Keine Sessions? Nein, keine Sessions? Aber, halt wir sind doch noch gar nicht am Ende. Das: Womit ich gerade angefangen hatte, das können wir noch erweitern. Weil ja, es ist wahr: Mit meinem Webinterface-Mail-Client lassen sich alle Mailserver bedienen - vor allem wenn wir SSL einführen. Aber: Ich war doch gerade beim verschicken von Mails mit Anhängen. Und ich war mit meinen Gedanken wo anders: Ich war doch gar nicht dabei, andere Mailserver zu bedienen. Der Gedanke kam aus doppelter Richtung: Was ist denn mit Menschen, die viele Mail-Konten haben? Und, was ist mit den Anhängen? Was sind Anhänge? Dateien - aha. Und woran denken wir bei Dateien und Mails? Ganz einfach: An Adressbücher. Und Termine. Es gibt Dateien, die Adressen speichern und es gibt Dateien, die Termine speichern. Also, was wir jetzt programmieren. Unabhängig vom allgemeinen Mail-Client und unabhängig von Sessions und damit, dass unser Mail-Client noch kein SSL unterstützt und keine Anhänge richtig darstellt. Wir werden uns jetzt gleich dem zu: Wir schreiben mit mySQL und einem Webinterface, eine Möglichkeit Termine und Adressen zu speichern. Und diese in einer allgemeingültigen Datei zu speichern.




Aber jetzt machen wir erst Mal das mit dem Attachment fertig und dann lege ich mich schlafen.




Yeeeapeaahhh! Es ist mir gelungen einen Anhand zu verschicken! Es hat funktioniert.




<html> <head>Dave Vajda's Webmail</head> <body> <form method="post"> <fieldset> <legend>Webmail using postfix and telnet and PHP</legend> <label for="Send a mail"> </label> <table> <tr><td>From:</td><td> <input type="text" name="from" size="100"></td></tr> <tr><td>To:</td><td> <input type="text" name="to" size="100"></td></tr> <tr><td>Subject:</td><td> <input type="text" name="subject" size="100"></td></tr> <tr><td>Username:</td><td> <input type="text" name="username" size="100"></td></tr> <tr><td>Password:</td><td> <input type="password" name="password" size="100"></td></tr> <tr><td></td><td> <textarea rows="40" cols="60" name="data">Hallo dies ist eine mail.talkortell.de Mail</textarea></td></tr> </table> <input type="Submit" value="Send Mail"> </fieldset> </form> <?php error_reporting(E_ALL); echo "<h2>Dave Vajda's Webmail</h2>\n"; /* Den Port für den WWW-Dienst ermitteln. */ $service_port = getservbyname('smtp', 'tcp'); /* Die IP-Adresse des Zielrechners ermitteln. */ $address = gethostbyname('192.168.178.28'); /* Einen TCP/IP-Socket erzeugen. */ $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket === false) { echo "socket_create() fehlgeschlagen: Grund: " . socket_strerror(socket_last_error()) . "\n"; } else { echo "OK.\n"; } echo "Versuche, zu '$address' auf Port '$service_port' zu verbinden ..."; $result = socket_connect($socket, $address, $service_port); if ($result === false) { echo "socket_connect() fehlgeschlagen.\nGrund: ($result) " . socket_strerror(socket_last_error($socket)) . "\n"; } else { echo "OK.\n"; } $thedate = gmdate('D, d M Y H:i:s T'); $in = "HELO mail.talkortell.de\n"; $in .= "AUTH LOGIN\n"; $in .= base64_encode ($_POST["username"]); $in .= "\n"; $in .= base64_encode ($_POST["password"]); $in .= "\n"; $in .= "MAIL FROM: " . $_POST["from"] . "\n"; $in .= "RCPT TO: " . $_POST["to"] . "\n"; $in .= "DATA\n"; $in .= "From: " . $_POST["from"] . "\n"; $in .= "To: " . $_POST["to"]. "\n"; $in .= "Subject: " . $_POST["subject"] . "\n"; $in .= "Date: " . $thedate . "\n"; $in .= "Message-ID: <" . time() . "@talkortell.de>\n"; $in .= "MIME-Version: 1.0\n"; $in .= "Content-Type: multipart/mixed; boundary=61723ghad12763231had\n"; $in .= "--61723ghad12763231had\n"; $in .= $_POST["data"] . "\n\n"; $in .= "MIME-Version: 1.0\n"; $in .= "--61723ghad12763231had\n"; //$in .= "Content-Type: multipart/mixed; name=davidvajda.png\n"; $in .= "Content-Transfer-Encoding: base64\n"; $in .= "content-Disposition: attachment; filename=davidvajda.png\n\n"; $in .= base64_encode(file_get_contents("davidvajda.png")) . "\n\n"; $in .= "--61723ghad12763231had--\n"; $in .= ".\n"; $in .= "QUIT\n"; $out = ''; echo $in; socket_write($socket, $in, strlen($in)); echo "OK.\n"; echo "Serverantwort lesen:\n\n"; while ($out = socket_read($socket, 2048)) { echo $out; } echo "Socket schließen ..."; socket_close($socket); echo "OK.\n\n"; ?> </body> </html>




Termin-Kalender

So, meine Damen und Herren heute muss ich lernen. Heute morgen, deswegen programmiere ich heute morgen nicht viel. Ich möchte aber darauf hinweisen, das Mail-Webinterface hat genau den Nachteil: Zwar können sich mehrere user gleichzeitig in einer telnet-Sitzung einloggen - so, dass mehrere user gleichzeitig eine Mail verschicken, bei den Attachments ist es aber so: Hier brauchen wir entweder (1.) Sessions oder wenigstens (2.) eine geschickte Dateinamenverwaltung. Sollten sonst zwei User gleichzeitig ein attachement verschicken, dann überschreiben sich beide. Das ist allerdings etwas, an dem muss noch gearbeitet werden. Woran möchte ich denn jetzt prorgrammieren? Ganz einfach: An der Kalender-App. Wenn man sich das jetzt mal in wikipedia anschaut, dann sieht eine iCalender-Datei, wie folgt aus:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:http://www.example.com/calendarapplication/
METHOD:PUBLISH
BEGIN:VEVENT
UID:461092315540@example.com
ORGANIZER;CN="Alice Balder, Example Inc.":MAILTO:alice@example.com
LOCATION:Irgendwo
GEO:48.85299;2.36885
SUMMARY:Eine Kurzinfo
DESCRIPTION:Beschreibung des Termines
CLASS:PUBLIC
DTSTART:20060910T220000Z
DTEND:20060919T215900Z
DTSTAMP:20060812T125900Z
END:VEVENT
END:VCALENDAR


Beispiel stammt aus wikipedia - Quelle: wikipedia. Und es gibt jetzt zwei Möglichkeiten zu arbeiten: (1.) Das Benutzerinterface (2.) die Speicherung in einer Datenbank. Und das leitet uns zu einem schönen Gedanken weiter: Natürlich würden wir normalerweise mit der Benutzerschnittstelle beginnen. Was wäre dafür nötig (1.1.) Die Darstellung im Kalender (1.2.) Etwas, das nur die Einträge darstellt, die dem Benutzer gehören. Das heißt: Wenn der Benutzer "david" heißt, werden in der Sitzung nur die Termine von "david" dargestellt. Wie speichern wir eigentlich die Einträge in der Datenbank? Gibt es für jeden user eine Tabelle? Und die Antwort lautet "nein". Es exisitier eine Tabelle für alle User. Aber: Wir beginnen nicht mit dem Benutzerinterface, sondern mit der Speicherung in der Datenbank. Die Tabelle enthält dabei Einträge, wie: UID, ORGANIZER, LOCATION, GEO, ... Dazu kommt aber BENUTZERNAME und ggf. PASSWORT. Und wir machen das jetzt so: Wir laden diese Datei nach oben, und sie wird in die Datenbank übernommen, wenn der Benutzername und das Passwort stimmt. Dann werden die Einträge in der Datenbank und allgemeinen Tabelle gespeichert. Es stellt sich aber die Frage, wie: Wir speicher, zu jedem Eintrag: UID, ORGANIZER, ..., USERNAME, PASSWORD. Aber mit dem Passwort können wir alle Daten verschlüsseln. Und so machen wir das: Wir speichern die Einträge nicht Klar-Text, wir verschlüsseln sie mit dem Passwort und speichern sie verschlüsselt. Wir speichern aber auch den Benutzernamen USERNAME verschlüsselt. Mit dem Passwort. Und verschlüsseln sogar das Passwort PASSWORD mit dem PASSWORD verschlüsselt. Wenn jetzt, der User eine Abfrage startet, dann wird nicht nur ein einzelnes Datum angezeigt, sondern es werden alle Einträge angezeigt. Ein Kalender dient nicht dazu, einzelne Einträge an zu zeigen, sondern den kompletten Kalender. Dazu gibt er ein Mal Benutzernamen und Passwort ein. Das Passwort, dass er eingibt wird mit dem Passwort verschlüsselt. Und so steht es in der Tabelle und der Datenbank. Dann gibt es eine

SELECT * FROM Table WHERE PASSWD = encryptedPasswd AND USERNAME = encryptedUsername

Und diese lifert alle verschlüsselten Einträge. Jeder dieser Einträge wird mit dem Passwort entschlüsselt. Dabei werden aber durch die SELECT * FROM abfrage, nur die Einträge angezeigt die dem User gehören. Denn nur die mit dem Passwort verschlüsselten Username, die zum Usernamen gehören, ergeben den entsprechenden verschlüsselten Usernamen. So, jetzt schreibe ich den Kalender. Also, was brauchen wir? Benutzerschnittstellen gibt es zwei:
  1. Entweder wir geben die Daten direkt über ein Webinterface ein
  2. Oder wir laden eine iCalender-Datei nach oben.
Wir wollen uns jetzt erst ein Mal gar nicht mit dem Benutzerfrontend herumplagen. Aber uns fällt auf: Das Benutzerfrontend besteht aus zwei Teilen:
  1. Der Eingabe
  2. Der Ausgabe
Was uns aus Sicht der Informatik natürlich erscheinen will, ist es nicht. Man denke an unseren Web-Interface-Mail-Client. Hier geben wir Daten scheinbar nur ein. Und warum ist das so? Ganz einfach: Wir schreiben die Mail, aber die Mail geht an den nächsten Mail-Server. Ist sie da, wird sie da gelesen. Wir haben also keine Ausgabe - jedenfalls nicht auf unserem Mailclient. Die Ausgabe ist irgendwo anders im Netz. Betrachten wir zum Beispiel die Berechnung von Reihen. Hier verbindet sich eine ganz einfache Eingabe, mit einer ganz einfachen Ausgabe. Als Eingabe kommt nämlich nur in Frage: Die untere Grenze, die obere Grenze und die Elemente der Reihe und als Ergebnis genügt eine kleine Zahl, nämlich das Ergebnis der Reihe. Scheinbar verweben sich hier Ein-und Ausgabe zu etwas gemeinsamen. Und das sind wir aus der Mathematik gewöhnt: Wenn wir einen Ausdruck hinschreiben, der Eingabewerte hat, steht gleich daneben, auf der anderen Seite der Gleichung das Ergebnis. Was bei dieser Reihe am Arbeiten ist, ist das, was drin ist. Hier ist ein kleiner Compiler im Spiel. Und dieser erledigt die Hauptarbeit und Ein- und Ausgabe sind dagegen etwas ganz simples. Es ist ein kleines Programm: Einen Compiler für arithmetische Ausdrücke und Reihen zu schreiben ist einfach. Vergleicht man aber die Komplexität von dem was drin ist und dem was draußen ist, ist das, was drinnen ist, viel mehr. Bei einem Calender ist das etwas anderes: Die Ausgabe hat mit der Eingabe nicht unbedingt etwas zu tun. Denn laden wir eine iCalender-Datei nach oben, haben wir hier gar nichts mit dem eigentlichen Kalender zu schaffen. Und wir können ein Benutzerinterface verwenden, wo wir Datum für Datum, jede Eingabe eingeben. Auch, wenn wir auf den Kalender klicken, auf das Datum, den Tag, das Jahr, den Monat, dann geben wir die Daten trotzdem in Texteingabeboxen ein, das ist auch beim google-Kalender so üblich. Trotzdem hat die Ausgabe nichts mehr mit der Eingabe zu schaffen und: Die Ausgabe ist noch mal eine Angelenheit für sich: Hier müsste nämlich rein theoretisch eine Art Tabelle von Tagen pro Monat, unterschiedlich gut dargestellt werden. Zum Beispiel indem man eine normale Tabelle nimmt, oder indem man pro Tag, ein Bild nimmt, was in einer Tabelle angeordnet ist. Es gibt aber eine einfachere Art und Weise, einen Kalender von der Ausgabe zu erzeugen: Nämlich eine Liste mit allen Terminen, die ein User hat. Es geht jetzt aber darum, das "innere" des Kalenders zu programmieren. Und das gestaltet sich wieder in zwei Teile.
  1. Die Speicherung der Daten zu einem Termin
  2. Die Sicherheit. Denn wir gehen davon aus, dass alle Benutzer, dieselbe Datenbank und selbe Tabelle benutzen. Außerdem gehen wir davon aus, dass es viele Benutzer gibt, die diesen Kalender-Dienst nutzen. Dabei sollen die Daten aber so gespeichert sein, dass sie sich


  1. nicht vermischen, das heißt, jeder Eintrag soll nur bei dem entsprechenden Benutzer angezeigt werden
  2. Für die anderen nicht lesbar ist.
Was aus (2.) folgt, ist die Verschlüsselung und ein Eintrag im Terminkalender in der Tabelle der Datenbank besteht aus dem Eintrag, zusätzlich aber dem Benutzernamen und dem Passwort. Dabei wrid das Passwort mit sich selbst verschlüsselt und der Benutzername mit dem Passwort verschlüsselt. Greift der Benutzer auf seine Termine zu: Gibt er das Passwort ein. Das Passwort ist mit sich selbst verschlüsselt. Wenn jetzt das Passwort eingegeben wird, dann wird das Paswort in der Datenbank mit dem eingegebenen entschlüsselt, und wenn dabei das Passwort raus kommt, was der User eingebeben hat, dann ist das Passwort richtig. Die Verschlüsselung ist ganz einfach. Dafür gibt es PHP-Funktionen. Die aus Plain-Text, "normale Text"-Passwörter machen, "die nicht aus seltsamen Zeichen bestehen". Die Frage ist, wie finden wir denn die Einträge zu dem Benutzer, wenn der Benutzername verschlüsselt ist. Wenn wir in Datenbank gucken, dann wollen wir gleich alle Termine finden, die zum Benutzer gehören. Ganz einfach: Der User gibt Benutzername und Passwort ein, der Benutzername wird verschlüsselt und nach diesem verschlüsselten Benutzername schauen wir in der Datenbank. Wie finden wir denn alle Einträge zu einem Benutzer, mit SQL

SELECT * FROM table WHERE user="username" and password="password"

Unabhängig von der Sicherheit müssen wir jetzt die mySQL-Datenbank aufbauen und das besteht aus zwei Bereichen.
  1. Das eine ist die Schnittstelle zu PHP. D.h. wir müssen ja zum Beispiel beim SELECT-Befehl, die Daten mit PHP erhalten
  2. Wir müssen die Datenbank haben. Dazu erstellen wir mit mySQL eine Datenbank. Und legen eine Tabelle mit den entsprechenden
Spalten an. Aber: Woher wissen wir, wie diese Tabelle aussieht? Ganz einfach: Wir entnehmen die Einträge aus dem Standard-Format einer iCalender-Datei. So, und wo wir so weit sind, fällt mir gleich auf. Wir haben eine Datenbank, die heißt zum Beispiel talkortellcalender. Darin haben wir die Tabelle, talkortellcalenderdates. Wir brauchen aber noch eine Tabelle talkortellcalenderusers. Denn wir wollen eine Tabelle in der jeder User gespeichert wird, mitsamt Passwort. Zwar könnten wir darauf verzichten, denn, wenn der User sein Passwort und seinen Namen eingibt, wird automatisch aus der Tabelle mit den Kalendereinträgen, jeder rausgefischt, der zu ihm gehört, vorrausgesetzt das Passwort stimmt, das tut es aber nur, wenn der Benutzername richtig ist. Allerdings: Es ist trotzdem sicherlich irgendwo besser, eine Tabelle mit Benutzername und Passwort zu haben. Für die mysql-Datenbank lauten die Befehle:

$mysql > CREATE DATABASE talkortellcalender;
> USE talkortellcalender;
> CREATE TABLE talkortellcalenderdates (username VARCHAR(48), password VARCHAR (64), PRODID VARCHAR (128), UID VARCHAR (128), ORGANIZER VARCHAR (256), LOCATION VARCHAR (128), GEO VARCHAR (128), SUMMARY VARCHAR (256), DESCRIPTION VARCHAR (256), DTSTART VARCHAR (128), DTEND VARCHAR (128), DTSTAMP VARCHAR (128));
> CREATE TABLE talkortellcalenderusers (username VARCHAR(48), password VARCHAR(64));

wenn, die Einträge in einer iCalender-Datei lauten, wie wikipedia zu entnehmen ist:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:http://www.example.com/calendarapplication/
METHOD:PUBLISH
BEGIN:VEVENT
UID:461092315540@example.com
ORGANIZER;CN="Alice Balder, Example Inc.":MAILTO:alice@example.com
LOCATION:Irgendwo
GEO:48.85299;2.36885
SUMMARY:Eine Kurzinfo
DESCRIPTION:Beschreibung des Termines
CLASS:PUBLIC
DTSTART:20060910T220000Z
DTEND:20060919T215900Z
DTSTAMP:20060812T125900Z
END:VEVENT
END:VCALENDAR


Jetzt kommt das Webinterface für die Eingabe. Wie sieht das aus? Ich habe mich entschieden: Ich sagte, ich habe eine zweite Tabelle, mit user und password, noch mal Extra. Obwohl in der Tabelle für jeden Eintrag im Kalender das Passwort und der Benutzername verschlüsselt gespeicher ist. Ich werde mich dieser zweiten Tabelle doch nicht bedienen. Es macht nichts, dass diese angelegt ist, notfalls ist sie halt leer, das hat keine Auswirkung auf die andere Tabelle. Aber: Das macht die Sache einfacher, diese zweite Tabelle nicht zu verwenden. Denn diese Tabelle impliziert, dass bevor wir irgendeinen Zugriff tun, wir in dieser Tabelle zunächst nachschauen, ob der Benutzername und das Passwort da ist. Und ansonsten, wenn dem nicht der Fall ist, wir den Zugriff nicht erlauben. Was aber jetzt entsteht, ist etwas seltsames, nämlich: Wir sind wieder bei den berühmten Sessions: Wenn der Benutzer, erst Benutzername und Passwort eingeben muss und dann erst zum Hauptteil weitergeleitet wird, dann brauchen wir Sessions. Nein, das stimmte nicht, was ich jetzt sagte. Damit tue ich mich immer etwas schwer. Wenn in einem PHP-Skript echo steht, dann erzeugt diese Echo eine Ausgabe, die dynamisch auf dem Rechner angezeigt wird, der gerade Zugriff hat, auf dem Client. Das kann man sich vorstellen, wie eine Popup-Box. Und diese ist ja auch irgendwo dynamisch drin. Nur, dass bei echo, der Code in der Seite selber steht, aber: Die HTML-Datei wird nicht durch die Ausgabe von echo verändert. Wenn man eine HTML-Datei verändert, dann müsste man sich vorstellen: Diese Datei wird physisch als Datei verändert. Dazu gibt es einen Befehl: get_file_contents() und zum Schreiben eben: file_put_contents. Diese PHP-Funktionen verändern Dateien auf dem Server und können natürlich auch die HTML-Datei selber verändern. Wissen Sie, warum bei mir immer dieser Aberglaube entsteht? Das ist ganz einfach: Weil ich den gnuplot ins Netz integriert habe, auf meine Homepage und, weil ich meine kleine Version eines Forums geschrieben habe. Und bei der kleinen Version des Forums wird tatsächlich auf die HTML-Datei des Forums, file_put_contents angewendet. Das erzeugt in mir schnell einen Aberglauben. Aber es geht weiter: Man schaue sich den integrierten gnuplot an. Wenn man sich den anschaut, dann entsteht hier ein png, gif oder svg, oder jpeg. Und dieses wird mit gnuplot erzeugt und auf der Platte gespeichert. Das ist etwas anderes. Das Problem ist nämlich: Wenn jetzt ein neuer user kommt, während der andere drin ist, wird dieses Bild überschrieben, mit der neuen Funktion. Generell kein Problem, in diesem einfachen Fall: Weil: Der User, der seine Funktion vorher erzeugt hat, hat am Bildschirm, solange er nicht aktualsiert, das alte Bild. Und der neue, das neue Bild. Speicher aber der erste User das Bild, kriegt er das vom anderen. Dieses Beispiel lässt uns aber schnell auf ein anderes Beispiel schließen: Nämlich ping - zum Beispiel, nslookup. Dieser erzeugen ja eine Ausgabe über die Standardein- und Ausgabe. Und ping und nslookup und dig und traceroute und so weiter, sind Programme, die standardmäßig bei Linux mit dabei sind. Aber sie gehören in die Konsole. Aufgerufen werden sie bei PHP, mit dem system()-Befehl. Dieses ruft ausführbare Programme auf, also Linux-Kommandos. Dasselbe gilt auch für den gnuplot. Und das lässt schnell in uns eine Verwechslung entstehen: Denn: Wir rufen sowohl gnuplot, als auch ping mit system() auf. Allerdings: gnuplot erzeugt tatsächlich ein Bild, das als eigene Datei gespeichert wird und auf dem Rechner liegt und dann in die HTML-Datei eingebunden wird. ping dagegen erzeugt eine Ausgabe über die Standardein- und Ausgabe. Allerdings, diese wird mit echo ausgegeben, im PHP-Programm. Aber: Dieses echo erzeugt keinen statischen Output in der HTML-Datei. Nur, was passiert, wenn zwei Nutzer gleichzeit ping aufrufen. Wenn zwei Nutzer gleichzeitig gnuplot aufrufen, dann ist das nicht so gut. Warum? Weil sich das eine Bild mit dem anderen überschreibt. Aber: Das ist nicht das Problem von gnuplot, sondern vom output, vom Bild. Aber: gnuplot und ping, können beliebig oft aufgerufen werden. Das sind halt viele Prozesse und wir können ping und gnuplot als Prozesse oft aufrufen. Und genauso, wie alle diese pings und digs und gnuplots in einem eigenen Prozess laufen, tun es die echos. Die echos des PHP des apache2-Webservers laufen in einem eigenen Prozess. Und das ist typisch, für Server eben. Denn: Das gilt sowohl für den Webserver apache2, als auch für postfix. Es können sich viele in eine Homepage einloggen und sie kriegen alle das selbe zu sehen. Und trotzdem besteht jedes Mal eine eigene Verbindung zum Server. Jeder Nutzer hat eine eigene Verbindung zum Server, mit eigenen IP-Adresse. Und für jeden Nutzer, läuft in apache2, quasi ein eigener Prozess. Ebenso, beim Mailserver. Zu einem Mailserver können 1.000.000 Leute gleichzeitig problemlos eine Verbindung aufbauen und Mails abrufen, auch, wenn scheinbar nur ein postfix-Mailserver läuft. Das ist letzten Endes ein Geheimnis von Servern und Dämonen. Weil in jedem apache2-Webserver und in jedem postfix laufen quasi mehrere Prozesse gleichzeitig, das gilt auch für die echo's. Aber jetzt zurück zur Sache: Die Eingabe wird ganz einfach - obwohl wir hier wieder vor dem alten Problem stehen. Was ist denn die Eingabe? Ganz einfach: Eine iCalender-Datei, damit wir auch wirklich sehen, es hält sich an die Schnittstellen, das ist uns wichtig - und der Benutzername und ein Passwort. Jetzt stehen wir wieder vor dem alten Problem: Denn hier wird eine iCalender-Datei nach oben geladen. Wenn jetzt gleichzeitig mehrere Benutzer eine hochladen und wir die Dateinamen nicht so vergeben, dass sie nicht gleich sind, überschreiben sie sich. Wenn die Dateinamen geschickt vergeben werden, aber 4*1024*1024*1024 Nutzer gleichzeitig eine iCalender-Datei nach oben laden, haben wir 4.000.000.000 Dateien auf dem Computer. Das wollen wir nicht. Denn bei der Größe von 512 Byte, sind das alleine, 2 Terra Byte. Da ist die Frage, was das bessere Übel ist: Eine überschrieben iCalender-Datei eines Users, oder die Schwachstelle, die alle Nutzer ausnützen könnten, nämlich: So viel nach oben laden, bis auf dem Rechner garantiert kein Platz mehr ist. Wir müssen bedenken: Es gibt 4*1024*1024*1024 IP-Adressen. Das sind mehr als 4.000.000.000 IP-Adressen. Wenn jeder eine Datei nach oben lädt, die nur 1 Byte groß ist, sind das 4 GByte. Bei 512 Byte pro Datei, was selbst bei iCalender kein Ẁunder wären, wären das noch mal 512 = 1024/2 => 2 Terrabyte. Zugegebenermaßen. Das ist eine ganz grundsätzliche Schwachstelle von einfachen Homepages, die zum Beispiel einfache Foren erlauben. Es könnten auf einen Schlag alle Nutzer des gesamten Internets anmelden und schon ist kein Platz mehr auf der Platte. Noch schlimmer: Wenn die Platte nicht etwa eine mit mount eingebundene externe Festplatte ist, dann ist die / (Root)-Partition voll. Und, da kann man nur sagen: Zum Glück hat Linux eine Swap-Partition. Trotzdem, schon beim Starten, erzeugt Linux Log-Files. Das heißt, Dateien die protokollieren, was gerade los ist. Ist aber 0 Byte Platz in der Root-Partition, kann Linux unter Umständen nicht ein Mal mehr starten. Das ist neben dem Aussehen eines Forums, mit vielen Buttons und vielen drum rum, und der Sicherheit, die nicht nur darin besteht Passwörter zu verschlüsseln, sondern die Sessions so zu gestalten, dass niemand anderes diese benutzen kann, ein großes Problem. Denn: Der Platz ist schnell verbraucht. Und abhilfe schaffen können zwei Dinge: Zunächst, wir könnten unsere Partitionen immer weiter erweitern. Aber nicht mit einem System, bei dem wir Hangriffe tun müssen, sondern, mit einem System, was das automatisch macht. Wir wollen nicht für jeden Partition Hand anlegen und Daten kopieren. Was ist, wenn wir eine neue Festplatte bekommen. Meinetwegen unsere ist 2 Terrabyte groß, jetzt haben wir uns eine gekauft, die ist 4 Terrabyte groß. Gut, wir können diese da einhängen, wo die alte mit 2 Terrabyte ist. Jetzt sind leider die Daten auf der alten. Also müssen wir kopieren. Und dann müssen wir sie einbinden. Und das ist nicht mal so einfach wie man denkt. Um nämlich eine neue Partition ein zu binden, müssen die alte entfernen. Wenn wir jetzt aber zeitkritisch sind, das heißt, hier sind 200.000.000 Nutzer online, dann bedeutet das: Diese haben für kurze Zeit keinen Zugriff, solange wir das mit dem mounten machen. Abgesehen davon: Was wäre, wenn wir eine Bank wären? Nicht Facebook, wo die Nutzer, das benutzen und gucken, sondern eine Bank, wo in einer Sekunde x-Millionen Transaktionen stattfinden. Eine Bank kann nicht auch nur eine Pikosekunde abschalten, schon sind die Vorgänge gescheitert oder nicht protokolliert. Das Problem mit den Banken ist nicht das, was manche denken: Manche denken, was passiert, wenn das System zusammenbricht. Na ja, die Antwort ist etwas anders, als wir denken. Wir denken: Wenn das System zusammenbricht, dann bricht als ganzes zusammen. Das ist nicht richtig. Denn: Stellen wir uns das mal so vor: Wir haben sagen wir in Deutschland 20 Atomkraftwerke. Wenn das eine nicht tut, heißt das nicht, dass die anderen nicht tun. Die haben nichts miteinander zu tun. Das ist trotzdem ein Netz. Und das ist mit Autos auch so. Wenn das Auto in Tübingen nicht tut, dann tun die in Hamburg trotzdem. Bei Autos fragt da keiner, obwohl das ist ein Straßennetz ist. Trotzdem müssen wir uns die Banken so vorstellen: Natürlich können Computer ausfallen. Und deswegen muss man alles sichern. Und natürlich kann es eine Gas-Explosion beim Gas-Speicher in Tübingen geben und davon ist die Infrastruktur der VR-Bank betroffen. Trotzdem dürfen jetzt nicht alle Finanztranskationen zusammenbrechen. Und deswegen heißt das: Wir müssen die Daten verteilt speichern. Sie müssen zum Beispiel in Reutlingen und Tübingen gespeichert werden. Und das am Besten gespiegelt. Weil wenn der Gasspeicher in Tübingen beim SWT platzt, dann ist Reutlingen davon nicht betroffen. Aber, ich möchte darauf hinweisen: Das sind Probleme, mit denen haben wir nichts zu tun. Verstehen Sie: Solche Netze bauen wir nicht auf. Und deswegen muss man sich bei solchen Problemen nicht zu schade sein. Ich sagte vorher: Der 100-Base-T-Stecker war vorher draußen, also die Homepage weg. Das ist schön. Aber ich sagte, ich werde deswegen trotzdem gut tun. Und genau das ist es: Wir brauchen solche Systeme nicht. Das betrifft uns nicht. Wer solche Systeme aufbauen will, der muss generell sehr viel Platz haben, sehr viele Immobilien und sehr viele Computer. Damit kann ein Otto-Normal-Verbraucher im allgemeinen nicht dienen. Hier fließt das Kapital einer ganzen Bank zusammen. Aber zurück zum Thema: Nehmen wir mal an: Wir sind nicht die Volksbank, aber jemand, der einen Mail-Server anbietet. Sagen wir, wir betreiben ein soziales Netzwerk mit 200.000.000 Kunden. Das Problem ist jetzt unser Festplattenkontigent. Und ich behaupte, das ist das eigentliche Problem: Das Festplattenkontigent. Und dabei haben wir ein Problem: Wir fangen nicht mit 100 Servern an, oder 1000. Womit sollen wir anfangen? Wir fangen mit 20 an. Wir haben nicht viele Nutzer. Am Anfang. Also, nicht viele Server. Wer sagt uns eigentlich, wohin wir kommen. Wenn jeder Nutzer 1GByte hochlädt, sind wir bei sage und Schreibe 200.000 TerraByte. Bei normalen Platten von 2 Terrabyte haben wir 100.000 Platten. Wir wissen nicht, womit wir anfangen und wir wissen nicht, wo wir enden. Und, das bedeutet: Es geht noch weiter. Denn die Platten werden alt. Und sie werden langsam. Im Gegensatz zu neuen. Und sie gehen kaputt. Die Rechner werden besser. Wir haben eine Charge von 100 alten Rechnern und eine von 1000 neuen Rechner. Anstatt, dass wir jetzt irgendetwas tolles tun, nehmen wir einfach einen neuen Rechner, auf dem wir das System eingerichtet haben, aber anstatt, kluge Schritte zu tun, hängen wir ihn an das lokale Netz. Und schon beginnt die Arbeit. Denn eigentlich bedeutet dieser neue Rechner nur eines: Wir haben noch mehr Platz. Bei guten Systemen ist es üblich RAID zu verwenden. RAID bedeutet, mehrere Platten und trotzdem: Auf allen ist gleichzeitig dasselbe gespeichert. Abgesehen davon aber, möchten wir ein System haben, was in einer Hinsicht gut ist, nämlich: Wenn wir neuen Platz haben, ist der nicht auf eine Platte von 2 Terrabyte beschränkt. Weil 2 Terrabyte, das ist wortwörtlich ein nichts, oder sagen wir ein Cent Stück, im Gegensatz zu dem, was ein Millionär hat. Und: Wir wollen aber, wenn wir jetzt eine neue Platte nehmen, sagen wir der Verbrauch der Benutzer steigt und steigt und steigt, einfach einen neuen Computer nehmen und ihn dran schalten. Dazu brauchen wir einen Server, im lokalen Netz. Der, quasi die Aufgabe übernimmt, das angeschlossene Kontigent, so zu verteilen, dass es gleich im alten Kontigent enthalten ist. Was aber entscheidend ist, ist eigentlich der Linux-Befehl

mount

Denn, was wir bisher gewohnt sind, ist: Wenn wir mount benutzen, haben wir eine Partition. Das wollen wir aber nicht: Wir wollen viele Partitionen zu einer machen. Jetzt verbinden sich zwei Prinzipien: Das Netzlaufwerk NFS, das unser Server im lokalen Netz anbietet, aber auch ein mount-Befehl, der viele kleine Partitionen zu einer macht. Wir wollen nämlich eines nicht: Wir wollen keine verschiedenen Ordner für verschiedene Benutzer. Es wäre einfach, zu sagen, die Benutzer von damals sind in Ordner /xyz/soundso und die nächsten im anderen. Was ist,wenn die alten Benutzer anfangen Platz zu verbrauchen. Wir wollen eine Partition. Und dafür müssen wir mit mount besonders intelligent umgehen. Mit solchen Sachen, hat der Otto-Normalverbraucher aber nichts mehr zu tun. Und aus diesem Grund können wir von gewissen Dingen abstand nehmen. Ich habe einen Mailaccount, bei mx.supra-net.net. Und ich habe selber einen Mailserver mail.talkortell.de. Jetzt ist das so: mx.supra-net.net gehört natürlich zur Domain supra-net.net und die gehört Phillip Biermann in Tübingen. Und: Dieser hat sein Klientel und bietet einen Mailservice an. Die Frage ist, wie er das tut, und die Antwort ist einfach: Wer bei ihm einen Mailaccount haben will, der muss sich wohl oder übel persönlich bei ihm melden. Zum Beispiel indem man bei ihm anruft. Auch, wenn die Passwörter verändert werden sollen, muss man persönlich bei ihm vorsprechen. Und davon habe ich gelernt. Wer bei mir einen Mail-Account haben will, der muss sich wohl oder übel persönlich bei mir melden. Davon habe ich gelernt. Ich behaupte jetzt mal ganz streng: Wenn sich x-Millionen Kunden bei Herrn Biermann melden, dann würde der auch mal sagen: So, jetzt ist Schluss keine neuen Mail-Accounts mehr. Und ehrlich gesagt: Das ist der Grund, warum ich kein Webinterface mache, bei dem man sich automatisch, wie bei gmail anmelden kann, indem man etwas in eine Maske eingibt. Da können sich Hacker zu schaffen machen und ich habe 300.000.000 Accounts, die voll sind und nicht sicher genutzt werden. Und man muss sagen, ganz klar: Die Kapazitäten sind schnell erschöpft: Was ist, wenn man das telefonisch macht. Also, wenn man an Unitymedia denkt, dann sind da ständig Leute zu erreichen. Da gibt es eine Warteschleife, also einen Telefondienst. Das kann einer alleine einer einfach nicht machen. Und deswegen kann man sich solche Themen abschminken. Auf diesem Niveau, brauchen wir das nicht. Ganz einfach. Wenn man aber mal nachdenkt, dann bedeutet das eines: Wir können durchaus Sachen machen, nur: Wir müssen uns halt nicht darüber aufregen, wenn das 100-BaseT-Kabel, halt ein Mal draußen ist. Dann gibt es halt 30 Minuten keine Homepage. Dieses Level an Sicherheit brauchen wir nicht erfüllen, weil wir dieses Level so oder so nicht erfüllen und nicht erfüllen werden. Die Logik ist ganz einfach: Eine Gleichung: Was hat uns bewegt, das System sicher zu machen? Es gibt zwei Faktoren, die uns bewegen können, ein System sicher zu machen: Entweder es sind hochsensible Daten. Etwa, betreff der Raketensysteme der USA. Könnten andere schaffen, dieses System an zu zapfen, könnten sie von den USA aus alle Raketen so zünden, dass sie alle die USA treffen. Das wäre die größte Katastrophe, die es geben könnte. Die größte Katastrophe, die überhaupt geben könnte. Es gibt keine größere. Die absolute Katastrophe. Es gibt nur eine Katastrophe, die schlimmer wäre, nämlich Kernfusionsbombe, mit einem Ausmaß, dass, wenn es etwas gibt, was ich nicht weiß und nicht zu vermuten wagen, nämlich eine Kernfusionsbombe mit dem Ausmaß, dass sie die Erdatmossphäre zum Fusionieren bringt - wenn das physikalisch geht. Unter einem solchen Angriff, der die Erde in einen Stern verwandeln würde, sind die schlimmsten Katastrophen, Havarien von Kernkraftwerken wie in Tschernobyl oder Fukushima. Doch wir müssen bedenken: Selbst bei Fukushima oder Tschernobyl ist nicht das gesamte Japan oder die gesamte Ukraine zerstört. Außerdem handelt es sich um Strahlung und nicht um Zerstörung und außerdem um keinen Angriff, sondern einen Unfall. Daneben ist der Angriff mit einer Kernwaffe der schlimmste Angriff, den es geben kann. Was aber ist, wenn sämtliche Kernwaffen im eigenen Land durch fremde Macht gezündet werden? Das ist der schlimmste Angriff den es überhaupt geben kann. Das ist die eine Form, bei der wir Sicherheit brauchen. Hier haben wir es mit sensiblen Daten zu tun. Es gibt eine andere Form, bei der wir Sicherheit brauchen. Nämlich dann, wenn es darum geht, viele Nutzer gleichzeitig zu befriedigen.Nehmen wir mal an, es gibt auf der Welt 10 Bankkonten, die mit einer EC-Karte verknüpft sind. Wenn zum Beispiel jetzt das System zusammenbricht, dann wäre der Schaden schnell behoben. Jeder der 10 Leute redet mit dem Personal von der Bank und die Fehler bei den Transaktionen werden behoben. Wenn das allerdings 100.000.000 Leute, dann wird das kompliziert. Also, braucht man Sicherheit. Wenn man aber nur damit rechnet, sagen wir 1000 Kunden zu haben, dann ist die Sicherheit nicht nötig. Das gilt auch für Facebook. Nicht, die 1000 Kunden, sondern, dass sie Sicherheit brauchen. Den Schaden könnte Facebook nicht mit der Hand in Ordnung bringen. Wenn wiederum bei mir das System zusammenbricht, macht das nichts. Denn ich rechne nur mit 1000 bis 10.000 Kunden. Und, wenn jetzt in diesem 1.000.000.000 kommen, bricht mein System gnadenlos zusammen. Aber jetzt lautet ja die Logik: Je mehr Kunden, um so größer die Sicherheit. Aber jetzt denken sie mal nach: Ich rechne ja nur mit 1.000 bis 10.000 Kunden. Wenn das System zusammenbricht, weil 1.000.000.000 bricht es zusammen. Aber macht das was? Nein, weil ich rechne ja so oder so nur mit 1.000 Kunden und wenn es zusammenbricht, ist das ja egal. Weil 1.000 Kunden brauchen keine solche Sicherheit. Aber, es waren ja 1.000.000.000 da? Na ja, aber das ist doch egal. Dann bricht das System zusammen - und das ist eine Frage der Sicherheit. Die 1.000.000.000 werden am Ende so oder so nicht bedient. Und müssen sie auch nicht, warum auch? Und wissen sie, wenn dann der Computer nicht geht - dann egal: Dann schmeiße ich eben einen Großteil der Kundendaten einfach wieder raus? Ist das eine Frage der Sicherheit, Kundendaten raus zu schmeißen? Ja, aber das brauche ich eben nicht, weil ich 1.000 Kunde rechne. Umgekehrt, aus genau diesem Grund, würde ich niemals probieren zu viel in den Aspekt Sicherheit, 100%ig und so weiter zu investieren. Das lohnt bei so kleinen Systemen einfach überhaupt nicht. Es gilt nur eines zu verhindern: Man darf nicht zu lassen, dass sich 100.000.000 Mail-Accounts einrichten lassen. Das wäre ein Problem. Deswegen darf man hier keine Maske verwenden, bei denen sich Mail-Accounts einrichten lassen. Was die Foren betrifft, mein eigenes und das mit phBB3, dann ist die Antwort einfach: Mein eigenes: Gut: Aber: Da habe ich das Kontigent eben mit diesem mount beschränkt. Es gibt nämlich nicht nur die Möglichkeit, eine Festplatte zu mounten, sondern eine Datei. Und die ist 30 GByte groß. Mehr passt eh nicht rein. Und wenn schon. Dann ist eben der Computer voll und ich lösche ihn. Bei phBB3, ist das gute: Die Sicherheit ist gut. Das verhindert nicht, dass ich 10.000 Nutzer kriege. Und trotzdem, ich kann es irgendwann einstellen. Und auch hier kann ich löschen. Aber es sind keine Sicherheitslücken drin, die Dinge erlauben, die nicht sein sollten. Aus diesem Grund habe ich keinen Anspruch eine Homepage zu erschaffen, wie Facebook. Aber das betrifft auch alle Buttons und alles weitere. Aus diesem Grund habe ich keinen Anspruch eine Homepage zu erschaffen, wie Facebook. Aber das betrifft auch alle Buttons und alles weitere.




So, jetzt mache ich an dem Kalender weiter. Jetzt geht es darum, zunächst ein Mal, die Datei vom iCalender hoch zu laden. - Jetzt geht es um das Speichern von Kalendereinträgen - Dazu brauchen wir, die PHP-Funktion:

move_uploaded_file

Das lädt eine Datei vom lokalen Rechner in das Verzeichnis des Servers. Dazu schreibe ich jetzt ein PHP-Skript.

Also, was ich jetzt zunächst hingekriegt habe, ist, dass mein Webmail nicht nur einen Anhang verschickt, das ist mir ja bereits gestern gelungen, mit telnet, base64_encode, SMTP einen Anhang zu versenden, sondern diesen nun noch über die Form im PHP-Skript aus zu wählen. Das Lustige ist nämlich: Ich habe ja eine Art kleines Forum geschrieben. http://www.talkortell.de/messages6/showall.php Dabei kann ich auch Photos und Videos uploaden. Dabei war mir das mit dem upload prima gelunden. Dazu verwendet man in PHP die Funktion

move_uploaded_file()

Das Witzige ist, ich habe das jetzt wieder probiert und es wollte und wollte nicht gehen. Ich bin schier verzweifelt. Was ich nicht wusste, ist, dass move_uploaded_file keine einfachen Dateinamen zum Uploaden akzeptiert, sondern diese müssen über $_FILE angegeben sein. Und das überprüft die Funktion, ob sie das auch sind. Das tat auf ein Mal, allerdings beim Mail nicht mehr - also es tat beim Adressbuch. Warum, beim Mail nicht? Ganz einfach, weil: Das <form&> muss lauten:

<form method="post" enctype="multipart/form-data">

Und nicht einfach nur
, sonst geht es nicht. Jetzt kann ich Anhänge verschicken, die ich auch auswähle.




Und jetzt geht es echt:
http://www.talkortell.de/newwebmail/webmail5.php





Und jetzt zum Adressbuch: Jetzt muss die icalender Datei genauso nach oben geladen werden. Jetzt, wenn wir diese icalender nach oben geladen haben, müssen die Daten ausgelesen werden, anhand des Passworts, was gleich eingegeben wird verschlüsselt werden und dann müssen die verschlüsselten Daten, das verschlüsselte Passwort, der verschlüsselte Benutzername in der Datenbank gespeichert werden.




Die Webmail5 sieht übrigens so aus, nächster Beitrag.







0: <html>
1: <head>Dave Vajda's Webmail</head>
2: <body>
3: <form method="post" enctype="multipart/form-data">
4: <fieldset>
5: <legend>Webmail using postfix and telnet and PHP</legend>
6: <label for="Send a mail"> </label>
7: <table>
8: <tr><td>From:</td><td> <input type="text" name="from" size="100"></td></tr>
9: <tr><td>To:</td><td> <input type="text" name="to" size="100"></td></tr>
10: <tr><td>Subject:</td><td> <input type="text" name="subject" size="100"></td></tr>
11: <tr><td>Username:</td><td> <input type="text" name="username" size="100"></td></tr>
12: <tr><td>Password:</td><td> <input type="password" name="password" size="100"></td></tr>
13: <tr><td>Attachment:</td><td><input type="file" name="datei"></td></tr>
14: <tr><td></td><td> <textarea rows="40" cols="60" name="data">Hallo dies ist eine mail.talkortell.de Mail</textarea></td></tr>
15: </table>
16: <input type="Submit" value="Send Mail">
17: </fieldset>
18: </form>
19:
20: <?php
21: error_reporting(E_ALL);
22:
23: echo "<h2>Dave Vajda's Webmail</h2>\n";
24:
25: $upload_folder = './';
26: $filename = "mailattachment";
27: $extension = strtolower(pathinfo($_FILES['datei']['name'], PATHINFO_EXTENSION));
28: $new_path = $upload_folder.$filename.".".$extension;
29: move_uploaded_file($_FILES['datei']['tmp_name'], $new_path);
30: $filecontents = base64_encode(file_get_contents($new_path));
31: unlink($new_path);
32: $filename = $_FILES['datei']['name'];
33:
34: /* Den Port für den WWW-Dienst ermitteln. */
35: $service_port = getservbyname('smtp', 'tcp');
36:
37: /* Die IP-Adresse des Zielrechners ermitteln. */
38: $address = gethostbyname('192.168.178.28');
39:
40: /* Einen TCP/IP-Socket erzeugen. */
41: $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
42: if ($socket === false) {
43: echo "socket_create() fehlgeschlagen: Grund: " . socket_strerror(socket_last_error()) . "\n";
44: } else {
45: echo "OK.\n";
46: }
47:
48: echo "Versuche, zu '$address' auf Port '$service_port' zu verbinden ...";
49: $result = socket_connect($socket, $address, $service_port);
50: if ($result === false) {
51: echo "socket_connect() fehlgeschlagen.\nGrund: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
52: } else {
53: echo "OK.\n";
54: }
55:
56: $thedate = gmdate('D, d M Y H:i:s T');
57:
58: $in = "HELO mail.talkortell.de\n";
59: $in .= "AUTH LOGIN\n";
60: $in .= base64_encode ($_POST["username"]);
61: $in .= "\n";
62: $in .= base64_encode ($_POST["password"]);
63: $in .= "\n";
64: $in .= "MAIL FROM: " . $_POST["from"] . "\n";
65: $in .= "RCPT TO: " . $_POST["to"] . "\n";
66: $in .= "DATA\n";
67: $in .= "From: " . $_POST["from"] . "\n";
68: $in .= "To: " . $_POST["to"]. "\n";
69: $in .= "Subject: " . $_POST["subject"] . "\n";
70: $in .= "Date: " . $thedate . "\n";
71: $in .= "Message-ID: <" . time() . "@talkortell.de>\n";
72: $in .= "MIME-Version: 1.0\n";
73: $in .= "Content-Type: multipart/mixed; boundary=61723ghad12763231had\n";
74: $in .= "--61723ghad12763231had\n";
75: $in .= $_POST["data"] . "\n\n";
76: $in .= "MIME-Version: 1.0\n";
77: $in .= "--61723ghad12763231had\n";
78: //$in .= "Content-Type: multipart/mixed; name=davidvajda.png\n";
79: $in .= "Content-Transfer-Encoding: base64\n";
80: $in .= "content-Disposition: attachment; filename=" . $filename . "\n\n";
81: $in .= $filecontents . "\n\n";
82: $in .= "--61723ghad12763231had--\n";
83: $in .= ".\n";
84: $in .= "QUIT\n";
85: $out = '';
86:
87: echo $in;
88:
89: socket_write($socket, $in, strlen($in));
90: echo "OK.\n";
91:
92: echo "Serverantwort lesen:\n\n";
93: while ($out = socket_read($socket, 2048)) {
94: echo $out;
95: }
96:
97: echo "Socket schließen ...";
98: socket_close($socket);
99: echo "OK.\n\n";
100: ?>
101: </body>
102: </html>





Jetzt poste ich den Code für mein Adressbuch, so weit.







0: <!DOCTYPE html>
1: <html>
2: <head>
3: <meta charset="UTF-8" />
4: <title>Talk Or Tell - Stories!</title>
5: </head>
6:
7: <body>
8: <center>
9: <div style="width: 100%; background-image: linear-gradient(to top, white 40%, navajowhite 100%);position:fixed;"\>
10:
11: <table>
12: <tr>
13: <td width="15%">
14: <img width="100%" src="../talkortell1.png" class="img2">
15: </td>
16: <td width="60%">
17: <br><br>
18: <font size="64px" face="Times New Roman">
19: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stories <br>
20: </font>
21: </font>
22: </td>
23: </tr>
24: </table>
25:
26: <hr>
27: </div>
28: </center>
29:
30: <br><br><br><br><br><br><br><br>
31:
32: <form method="post" enctype="multipart/form-data">
33: <input type="file" name="datei"><br>
34: <input type="Submit" value="Hochladen">
35: </form>
36:
37: <?php
38: $extension = strtolower(pathinfo($_FILES['datei']['name'], PATHINFO_EXTENSION));
39: $allowed_extensions = array('ics', 'ifb', 'iCal', 'iFBf');
40: if(!in_array($extension, $allowed_extensions)) {
41: die('<script>alert("Ungültige Dateiendung. Nur iCalender-Formate sind erlaubt!");</script>');
42: }
43:
44: $max_size = 2048*8;
45: if($_FILES['datei']['size'] > $max_size) {
46: die('<script>alert("Bitte keine zu großen Dateien hochladen");</script>');
47: }
48:
49: $upload_folder = './';
50: $filename = "test";
51: $new_path = $upload_folder.$filename.".".$extension;
52: move_uploaded_file($_FILES['datei']['tmp_name'], $new_path);
53: $file_content = file_get_contents($new_path);
54: echo $file_content;
55:
56: $file_handle = fopen($new_path, 'r');
57: while (!feof($file_handle)) {
58:
59: $line = fgets($file_handle);
60: echo $line;
61: echo '<br>';
62: if(strstr($line, "BEGIN:VEVENT"))
63: break;
64: }
65:
66: while (!feof($file_handle)) {
67:
68: $line = fgets($file_handle);
69: echo '<br>';
70: if(strstr($line, "END:VEVENT"))
71: break;
72: else if(strstr($line, "UID:")) {
73: echo substr($line, strlen("UID:"));
74: $uid = substr($line, strlen("UID:"));
75: }
76: else if(strstr($line, "ORGANIZER;CN=")) {
77: echo substr($line, strlen("ORGANIZER;CN="));
78: $organizer = substr($line, strlen("ORGANIZER;CN="));
79: }
80: else if(strstr($line, "LOCATION:")) {
81: echo substr($line, strlen("LOCATION:"));
82: $location = substr($line, strlen("LOCATION:"));
83: }
84: else if(strstr($line, "GEO:")) {
85: echo substr($line, strlen("GEO:"));
86: $geo = substr($line, strlen("GEO:"));
87: }
88: else if(strstr($line, "SUMMARY:")) {
89: echo substr($line, strlen("SUMMARY:"));
90: $summary = substr($line, strlen("SUMMARY:"));
91: }
92:
93: }
94:
95: ?>
96: </body>
97: </html>








0: <!DOCTYPE html>
1: <html>
2: <head>
3: <meta charset="UTF-8" />
4: <title>Talk Or Tell - Adressbook!</title>
5: </head>
6:
7: <body>
8: <center>
9: <div style="width: 100%; background-image: linear-gradient(to top, white 40%, navajowhite 100%);position:fixed;"\>
10:
11: <table>
12: <tr>
13: <td width="15%">
14: <img width="100%" src="../talkortell1.png" class="img2">
15: </td>
16: <td width="60%">
17: <br><br>
18: <font size="64px" face="Times New Roman">
19: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Adressbook <br>
20: </font>
21: </font>
22: </td>
23: </tr>
24: </table>
25:
26: <hr>
27: </div>
28: </center>
29:
30: <br><br><br><br><br><br><br><br>
31:
32: <form method="post" enctype="multipart/form-data">
33: <input type="file" name="datei"><br>
34: <input type="Submit" value="Hochladen">
35: </form>
36:
37: <?php
38: $extension = strtolower(pathinfo($_FILES['datei']['name'], PATHINFO_EXTENSION));
39: $allowed_extensions = array('ics', 'ifb', 'iCal', 'iFBf');
40: if(!in_array($extension, $allowed_extensions)) {
41: die('<script>alert("Ungültige Dateiendung. Nur iCalender-Formate sind erlaubt!");</script>');
42: }
43:
44: $max_size = 2048*8;
45: if($_FILES['datei']['size'] > $max_size) {
46: die('<script>alert("Bitte keine zu großen Dateien hochladen");</script>');
47: }
48:
49: $upload_folder = './';
50: $filename = "test";
51: $new_path = $upload_folder.$filename.".".$extension;
52: move_uploaded_file($_FILES['datei']['tmp_name'], $new_path);
53: $file_content = file_get_contents($new_path);
54: echo $file_content;
55:
56: $file_handle = fopen($new_path, 'r');
57: while (!feof($file_handle)) {
58:
59: $line = fgets($file_handle);
60: echo $line;
61: echo '<br>';
62: if(strstr($line, "BEGIN:VEVENT"))
63: break;
64: }
65:
66: while (!feof($file_handle)) {
67:
68: $line = fgets($file_handle);
69: echo '<br>';
70: if(strstr($line, "END:VEVENT"))
71: break;
72: else if(strstr($line, "UID:")) {
73: echo substr($line, strlen("UID:"));
74: $uid = substr($line, strlen("UID:"));
75: }
76: else if(strstr($line, "ORGANIZER;CN=")) {
77: echo substr($line, strlen("ORGANIZER;CN="));
78: $organizer = substr($line, strlen("ORGANIZER;CN="));
79: }
80: else if(strstr($line, "LOCATION:")) {
81: echo substr($line, strlen("LOCATION:"));
82: $location = substr($line, strlen("LOCATION:"));
83: }
84: else if(strstr($line, "GEO:")) {
85: echo substr($line, strlen("GEO:"));
86: $geo = substr($line, strlen("GEO:"));
87: }
88: else if(strstr($line, "SUMMARY:")) {
89: echo substr($line, strlen("SUMMARY:"));
90: $summary = substr($line, strlen("SUMMARY:"));
91: }
92: else if(strstr($line, "CLASS:")) {
93: echo substr($line, strlen("CLASS:"));
94: $class = substr($line, strlen("CLASS:"));
95: }
96: else if(strstr($line, "DESCRIPTION:")) {
97: echo substr($line, strlen("DESCRIPTION:"));
98: $description = substr($line, strlen("DESCRIPTION:"));
99: }
100: else if(strstr($line, "DTSTART:")) {
101: echo substr($line, strlen("DTSTART:"));
102: $dtstart = substr($line, strlen("DTSTART:"));
103: }
104: else if(strstr($line, "DTEND:")) {
105: echo substr($line, strlen("DTEND:"));
106: $dtend = substr($line, strlen("DTEND:"));
107: }
108: else if(strstr($line, "DTSTAMP:")) {
109: echo substr($line, strlen("DTSTAMP:"));
110: $dtstamp = substr($line, strlen("DTSTAMP:"));
111: }
112:
113:
114: }
115:
116: ?>
117: </body>
118: </html>





Jetzt im nächsten Schritt speichern wir die mit SQL in der Datenbank.




So muss es richtig lauten, diesmal noch ohne verschlüsselte Speicherung und das stimmt









0: <!DOCTYPE html>
1: <html>
2: <head>
3: <meta charset="UTF-8" />
4: <title>Talk Or Tell - Calender!</title>
5: </head>
6:
7: <body>
8: <center>
9: <div style="width: 100%; background-image: linear-gradient(to top, white 40%, navajowhite 100%);position:fixed;"\>
10:
11: <table>
12: <tr>
13: <td width="15%">
14: <img width="100%" src="../talkortell1.png" class="img2">
15: </td>
16: <td width="60%">
17: <br><br>
18: <font size="64px" face="Times New Roman">
19: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Calender <br>
20: </font>
21: </font>
22: </td>
23: </tr>
24: </table>
25:
26: <hr>
27: </div>
28: </center>
29:
30: <br><br><br><br><br><br><br><br>
31:
32: <form method="post" enctype="multipart/form-data">
33: <input type="file" name="datei"><br>
34: <input type="Submit" value="Hochladen">
35: </form>
36:
37: <?php
38: $extension = strtolower(pathinfo($_FILES['datei']['name'], PATHINFO_EXTENSION));
39: $allowed_extensions = array('ics', 'ifb', 'iCal', 'iFBf');
40: if(!in_array($extension, $allowed_extensions)) {
41: die('<script>alert("Ungültige Dateiendung. Nur iCalender-Formate sind erlaubt!");</script>');
42: }
43:
44: $max_size = 2048*8;
45: if($_FILES['datei']['size'] > $max_size) {
46: die('<script>alert("Bitte keine zu großen Dateien hochladen");</script>');
47: }
48:
49: $upload_folder = './';
50: $filename = "test";
51: $new_path = $upload_folder.$filename.".".$extension;
52: move_uploaded_file($_FILES['datei']['tmp_name'], $new_path);
53: $file_content = file_get_contents($new_path);
54: echo $file_content;
55:
56: $file_handle = fopen($new_path, 'r');
57: while (!feof($file_handle)) {
58:
59: $line = fgets($file_handle);
60: echo $line;
61: echo '<br>';
62: if(strstr($line, "BEGIN:VEVENT"))
63: break;
64: }
65:
66: while (!feof($file_handle)) {
67:
68: $line = fgets($file_handle);
69: echo '<br>';
70: if(strstr($line, "END:VEVENT"))
71: break;
72: else if(strstr($line, "UID:")) {
73: echo substr($line, strlen("UID:"));
74: $uid = substr($line, strlen("UID:"));
75: }
76: else if(strstr($line, "ORGANIZER;CN=")) {
77: echo substr($line, strlen("ORGANIZER;CN="));
78: $organizer = substr($line, strlen("ORGANIZER;CN="));
79: }
80: else if(strstr($line, "LOCATION:")) {
81: echo substr($line, strlen("LOCATION:"));
82: $location = substr($line, strlen("LOCATION:"));
83: }
84: else if(strstr($line, "GEO:")) {
85: echo substr($line, strlen("GEO:"));
86: $geo = substr($line, strlen("GEO:"));
87: }
88: else if(strstr($line, "SUMMARY:")) {
89: echo substr($line, strlen("SUMMARY:"));
90: $summary = substr($line, strlen("SUMMARY:"));
91: }
92: else if(strstr($line, "CLASS:")) {
93: echo substr($line, strlen("CLASS:"));
94: $class = substr($line, strlen("CLASS:"));
95: }
96: else if(strstr($line, "DESCRIPTION:")) {
97: echo substr($line, strlen("DESCRIPTION:"));
98: $description = substr($line, strlen("DESCRIPTION:"));
99: }
100: else if(strstr($line, "DTSTART:")) {
101: echo substr($line, strlen("DTSTART:"));
102: $dtstart = substr($line, strlen("DTSTART:"));
103: }
104: else if(strstr($line, "DTEND:")) {
105: echo substr($line, strlen("DTEND:"));
106: $dtend = substr($line, strlen("DTEND:"));
107: }
108: else if(strstr($line, "DTSTAMP:")) {
109: echo substr($line, strlen("DTSTAMP:"));
110: $dtstamp = substr($line, strlen("DTSTAMP:"));
111: }
112:
113: }
114:
115: $servername = "localhost";
116: $dbname = "talkortellcalender";
117: $username = "root";
118: $password = "";
119:
120: // Create connection
121: $conn = new mysqli($servername, $username, $password, $dbname);
122: // Check connection
123: if ($conn->connect_error) {
124: die("Connection failed: " . $conn->connect_error);
125: }
126:
127: $uusername = "Hallo";
128: $upassword = "hallo";
129:
130: $sql = "INSERT INTO talkortellcalenderdates (username, password, UID, ORGANIZER, LOCATION, GEO, SUMMARY, DESCRIPTION, DTSTART, DTEND, DTSTAMP) VALUES ('" .$uusername . "', ' " . $upassword . "', ' ". $uid . "','" . $organizer . "','" . $location . "','" . $geo . "','" . $summary . "','" . $description . "','" . $dtstart . "','" . $dtend . "','" . $dtstamp . "')";
131:
132: if ($conn->query($sql) === TRUE) {
133: echo "New record created successfully";
134: } else {
135: echo "Error: " . $sql . "<br>" . $conn->error;
136: }
137:
138: $conn->close();
139:
140: ?>
141: </body>
142: </html>











Jetzt (1.) speichern wir die Daten verschlüsselt (2.) geben dem User noch die Möglichkeit die das Passwort und den Benutzernamen ein zu geben - das wurde in diesem Beispiel nämlich statisch im PHP-Programm als Test (!) angeben (3.) wir machen eine Weiterleitung zu einem PHP-Skript, dass sich auch mit der MySQL-Datenbank verbindet, dann aber: Den Benutzernamen und das Passwort erwartet und mit dem SQL-Befehl SELECT * FROM ... alle Termine ausliest, die vom Benutzer mit richtigen Passwort gespeichert wurden.




OK, in meiner Argumentation steckt ein Fehler. Aber jetzt stimmt es. Bestimmte Worte werden zum Beispiel mit md5() verschlüsselt. Zum Beispiel wird ein Passwort "abc" mit md5() verschlüsselt. Und ein Wort wird nicht mit einem Passwort verschlüsselt. Zum Beispiel bei md5(). Da jeden Falls nicht. Eigentlich, weiß ich das. Das sage ich gleich: Eigentlich, weiß ich das. Aber, der Prozess lautet nicht: Wort, mit Passwort verschlüsseln = Verschlüsselt Verschlüsseln mit Passwort verschlüsseln = Entschlüsselt Sondern wir nehmen ein Passwort und verschlüsseln das. Danach ist es verschlüsselt. Der Unterschied zwischen einem Passwort und einem Datum im Kalender, ist: Das Passwort, und auch den Benutzernamen, muss der User jedes Mal neu eingeben. Dabei bleibt aber das Passwort das Alte. Und das ist ein Unterschied! Denn, wenn der Benutzer das Passwort erneut eingibt, dann wird es wieder verschlüsselt. Es ist verschlüsselt gespeichert. Wenn das verschlüsselte Passwort, was eingegeben wurde, mit dem verschlüsselten Passwort übereinstimmt, was gespeichert wurde, dann ist das Passwort richtig. Die Frage ist aber, was ist mit den Kalenderdaten? Werden diese auch verschlüsselt. Und die Antwort lautet: Nein! Natürlich nicht! Das wäre fatal! Warum? Weil, wir können das Passwort jedes Mal vergleichen, weil es der Benutzer immer wieder eingibt. Dann wird es verschlüsselt. Aber wird es verschlüsselt wird es jedes Mal zum selben verschlüsselt. Es kommt nicht ein Mal das raus und ein Mal das. Aber: Diese "Verschlüsselten" können wir miteinander vergleichen. Was passiert aber, wenn wir die Daten verschlüsseln? Das gibt eine große Katastrophe, weil: Wir können die Daten verschlüsseln, aber nicht entschlüsseln. Das ist der Unterschied. Wir haben einen Schlüssel, zum Zu-Schließen, nicht zum Auf-Schließen. Und beim Passwort ist es ja so: Es wird verschlüsselt gespeichert und erneut verschlüsselt eingegeben. Das Resultat ist dasselbe. Was aber machen wir mit den Daten? Wir wissen ja nicht, was in den Daten steht. Im dämlichsten Falle müsste der Benutzer alle Daten erneut eingeben und man könnte schauen, ob er sie so gespeichert hat - blos, wozu brauche ich dann einen Kalender. Es gäbe eine intelligentere Methode: Ich prüfe jedes Datum, von "aaa" bis "zzz" und verschlüssele es. Wenn es mit dem verschlüsselt gespeicherten Datum übereinstimmt, dann ist das das Datum, was gespeichert wurde, blos, blöd: Das ist der Brute-Force-Algorithmus, mit dem man herausbekommt, was da eigentlich verschlüsselt wurde. Nur erstens möchte ich meine Datenbank nicht hacken müssen, zweitens: Der Brute-Force-Algorithmus würde selbst bei heutigen Computern 5h Minimum brauchen, bis er an das Datum kommt, wenn wir pech haben. Und dazu haben wir keine Lust. Immerhin wollen wir unsere Daten abfragen. Aber, was ist denn jetzt mit den Daten? Sind diese nicht verschlüsselt? Nein - sie sind es nicht. Was nutzt uns dann das Passwort? Und hier liegt der Teufel im Detail. Was wir eben mit den Sessions nicht getan haben, nämlich eine Sperre ein zu bauen, tun wir jetzt in unserer Datenbank. Denn wir verschlüsseln am Besten den Benutzernamen user und das Passwort gleichermaßen. Und damit die Daten wirklich nur an den User gelangen, der sie haben soll, müssen wir folgendes machen: Das liegt in der Macht von SQL die Daten nur dann raus zu geben, wenn Passwort und Benutzername übereinstimmen. Das machen wir mit der SQL-Abfrage:

SELECT * FROM talkortellcalenderdates WHERE password = ... AND username = ...;

Worauf es ankommt, ist das

WHERE password = ... AND username = ...;

Dann werden nämlich nur die Daten von SQL heraus gegeben, wo das Passwort und der Benutzername und zwar verschlüsselt stimmt. Eine Schwachstelle entdecken wir aber jetzt: Was ist, wenn diese SQL-Datenbank in die Hände anderer gerät. Und hier liegt ein Problem. Normalerweise können wir uns nämlich nur als root, superuser mit dem root-Passwort in die Datenbank einloggen. Das schafft uns aber Probleme, nämlich, dass SQL nicht so bequem mit apache2-Webserver und PHP zusammen läuft, auch, wenn es ginge. Deswegen der Befehl, in der Konsole - also in der Konsole, nicht PHP und SQL, ein Befehl, an den SQL-Server:

root@talkortell:/home/david/test3# service mysqld stop
root@talkortell:/home/david/test3# service mariadb stop
root@talkortell:/home/david/test3# mysqld_safe --skip-grant-tables --skip-networking


Das Problem ist, wenn wir uns nun in die Datenbank einloggen, können wir das ohne Passwort-Schutz tun. Ich rede jetzt nicht von den Passwörtern, die wir für unseren Kalender speichern, sondern von denen von unserer mySQL-Datenbank - unserem SQL-Server. Das ist ein Server. mySQL, mariadb, das sind Server, für Datenbanken. Und: In einen Server, können wir uns wie gewohnt, über die IP-Adresse in einen Server einlogen, wie bei apache2 oder postfix oder, anstatt über die IP-Adresse über den FQDN, indem Fall talkortell.de. Nur: Wir machen es auf unserem Rechner über localhost. localhost steht für 127.0.0.1. So weit so gut. So muss es auch sein: Weil unsere MySQL-Applikationen laufen auf unserem Rechner. Blos, was wir jetzt nicht mehr müssen, oder was apache2 nicht mehr muss, ist sich als root einloggen und wir müssen kein Passwort mehr für den Server eingeben. Das gilt, sage ich gleich, für unser localhost. Wir brauchen jetzt kein Passwort mehr. Da wir aber localhost verwenden und das etwas ist, das zu einem Netz gehört, und wir trotzdem im Netz sind, könnte jemand so schlau sein, die IP-Adresse von www.talkortell.de eingeben, oder talkortell.de und er könnte gleich drin sein, in unserer Datenbank. Wie kommt er eigentlich da drauf, dass bei uns mySQL läuft? Ganz einfach: Weil wir haben ja einen Calender geschrieben und wir haben ein kleine Art von Forum geschrieben und damit angegeben, wir benutzen mySQL. Also könnte derjenige wissen, OK, da läuft ein MySQL-Server und der darf nicht offen sein. Sonst geht der da rein. Das in sich, für den Calender wäre kein Problem. Aber wir benutzen auch phBB3 und das soll ein anständiges Forum sein, das wiederum benutzt MySQL - dann wäre das Mist. Vor allem, da auch phBB3 verrät: Hier wird MySQL verwendet. Zum Glück gibt es zwei Sicherheitsmechanismen, die das verhindern:

--skip-networking

Zweitens: Die Portfreigabe. Unsere MySQL-Datenbank ist wie der apache2-Webserver und der postfix-Mail-Server ja ein Server. Und von apache2 mit HTTP wissen wir er läuft auf Port 80. Und von postfix auf Port 25 und 587. Und von dovecot mit IMAP auf 143 und 993 und von dovecot und POP3 auf 110 und 990. Da der Port für die mySQL-Datenbank nicht freigegeben ist, kann auch keiner in den MySQL/MariaDB-Server rein. Und: Der Port für die MariaBD-Datenbank liegt bei irgendwas mit 6, 5 und 3 und ist eine 4 Stellige Zahl.

Aber, wer sich freut, der hat sich zu früh gefreut: Man käme irgendwo rein, weil immerhin wir verwenden ja eine MariaDB-Datenbank und MySQL in unserem PHP-Skript. Außerdem sind wir am Netz und haben einen HTTP-Server, der auch noch MySQL verwendet. Kommt man da rein? Nein! Warum eigentlich? Weil der MySQL-Server lokal auf dem Rechner läuft und: Natürlich kommen wir auf unserem lokalen Rechner da rein, weil wenn wir nicht mehr rein kommen, dann brauchen wir gar keine Datenbank mehr. Und: Warum ist die dann mit dem Netz verbunden? Ganz einfach: Die Anfragen, die über den HTTP-Server an MariaDB und MySQL gestellt werden laufen lokal auf dem Rechner, auf dem der Server ist. Auch, wenn der HTTP-Server öffentlich ist, die Anfragen gehen lokal an MariaDB und MySQL.

Jetzt sind wir mit dem ersten Teil schon fertig, nächster Beitrag. Im nächsten Schritt, werden wir das zweite PHP-Skript schreiben, von dem wir im ersten einen Hyperlink anbringen. Im zweiten Teil geben wir den Benutzernamen und das Passwort ein und machen eine SQL-Abfrage in die andere Richtung: Jetzt lesen wir mit SELECT alle Daten aus, die zum Benutzernamen passen.







0: <!DOCTYPE html>
1: <html>
2: <head>
3: <meta charset="UTF-8" />
4: <title>Talk Or Tell - Calender!</title>
5: </head>
6:
7: <body>
8: <center>
9: <div style="width: 100%; background-image: linear-gradient(to top, white 40%, navajowhite 100%);position:fixed;"\>
10:
11: <table>
12: <tr>
13: <td width="15%">
14: <img width="100%" src="../talkortell1.png" class="img2">
15: </td>
16: <td width="60%">
17: <br><br>
18: <font size="64px" face="Times New Roman">
19: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Calender <br>
20: </font>
21: </font>
22: </td>
23: </tr>
24: </table>
25:
26: <hr>
27: </div>
28: </center>
29:
30: <br><br><br><br><br><br><br><br>
31:
32: <form method="post" enctype="multipart/form-data">
33: <input type="text" name="username"><br>
34: <input type="password" name="password"><br>
35: <input type="file" name="datei"><br>
36: <input type="Submit" value="Hochladen">
37: </form>
38:
39: <?php
40: $extension = strtolower(pathinfo($_FILES['datei']['name'], PATHINFO_EXTENSION));
41: $allowed_extensions = array('ics', 'ifb', 'iCal', 'iFBf');
42: if(!in_array($extension, $allowed_extensions)) {
43: die('<script>alert("Ungültige Dateiendung. Nur iCalender-Formate sind erlaubt!");</script>');
44: }
45:
46: $max_size = 2048*8;
47: if($_FILES['datei']['size'] > $max_size) {
48: die('<script>alert("Bitte keine zu großen Dateien hochladen");</script>');
49: }
50:
51: $upload_folder = './';
52: $filename = "test";
53: $new_path = $upload_folder.$filename.".".$extension;
54: move_uploaded_file($_FILES['datei']['tmp_name'], $new_path);
55: $file_content = file_get_contents($new_path);
56: echo $file_content;
57:
58: $file_handle = fopen($new_path, 'r');
59: while (!feof($file_handle)) {
60:
61: $line = fgets($file_handle);
62: echo $line;
63: echo '<br>';
64: if(strstr($line, "BEGIN:VEVENT"))
65: break;
66: }
67:
68: while (!feof($file_handle)) {
69:
70: $line = fgets($file_handle);
71: echo '<br>';
72: if(strstr($line, "END:VEVENT"))
73: break;
74: else if(strstr($line, "UID:")) {
75: echo substr($line, strlen("UID:"));
76: $uid = substr($line, strlen("UID:"));
77: }
78: else if(strstr($line, "ORGANIZER;CN=")) {
79: echo substr($line, strlen("ORGANIZER;CN="));
80: $organizer = substr($line, strlen("ORGANIZER;CN="));
81: }
82: else if(strstr($line, "LOCATION:")) {
83: echo substr($line, strlen("LOCATION:"));
84: $location = substr($line, strlen("LOCATION:"));
85: }
86: else if(strstr($line, "GEO:")) {
87: echo substr($line, strlen("GEO:"));
88: $geo = substr($line, strlen("GEO:"));
89: }
90: else if(strstr($line, "SUMMARY:")) {
91: echo substr($line, strlen("SUMMARY:"));
92: $summary = substr($line, strlen("SUMMARY:"));
93: }
94: else if(strstr($line, "CLASS:")) {
95: echo substr($line, strlen("CLASS:"));
96: $class = substr($line, strlen("CLASS:"));
97: }
98: else if(strstr($line, "DESCRIPTION:")) {
99: echo substr($line, strlen("DESCRIPTION:"));
100: $description = substr($line, strlen("DESCRIPTION:"));
101: }
102: else if(strstr($line, "DTSTART:")) {
103: echo substr($line, strlen("DTSTART:"));
104: $dtstart = substr($line, strlen("DTSTART:"));
105: }
106: else if(strstr($line, "DTEND:")) {
107: echo substr($line, strlen("DTEND:"));
108: $dtend = substr($line, strlen("DTEND:"));
109: }
110: else if(strstr($line, "DTSTAMP:")) {
111: echo substr($line, strlen("DTSTAMP:"));
112: $dtstamp = substr($line, strlen("DTSTAMP:"));
113: }
114:
115: }
116:
117: $servername = "localhost";
118: $dbname = "talkortellcalender";
119: $username = "root";
120: $password = "";
121:
122: // Create connection
123: $conn = new mysqli($servername, $username, $password, $dbname);
124: // Check connection
125: if ($conn->connect_error) {
126: die("Connection failed: " . $conn->connect_error);
127: }
128:
129: $uusername = $_POST['username'];
130: $upassword = $_POST['password'];
131:
132: $sql = "INSERT INTO talkortellcalenderdates (username, password, UID, ORGANIZER, LOCATION, GEO, SUMMARY, DESCRIPTION, DTSTART, DTEND, DTSTAMP) VALUES ('" .md5($uusername). "', ' " . md5($upassword) . "', ' ". $uid . "','" . $organizer . "','" . $location . "','" . $geo . "','" . $summary . "','" . $description . "','" . $dtstart . "','" . $dtend . "','" . $dtstamp . "')";
133:
134: if ($conn->query($sql) === TRUE) {
135: echo "New record created successfully";
136: } else {
137: echo "Error: " . $sql . "<br>" . $conn->error;
138: }
139:
140: $conn->close();
141:
142: ?>
143: </body>
144: </html>





Was dann noch für ein Schritt folgen wird, ist folgender: Wir müssen natürlich die Datenbank nicht einfach ausgeben, sondern dann geht es an das User-Interface, dass den Kalender auch als Kalender darstellt.




Ich bin jetzt fertig und zwar erfolgreich. Allerdings war noch ein Fehler drin. Bei dem verschlüsselten Passwort war nämlich vorne noch ein Leerzeichen zu viel und so wurde es in der Datenbank gespeichert. Das bedeutet, wir finden es nachher nicht, weil im Datum selber noch ein Leerzeichen ist.


0: <!DOCTYPE html>
1: <html>
2: <head>
3: <meta charset="UTF-8" />
4: <title>Talk Or Tell - Calender!</title>
5: </head>
6:
7: <body>
8: <center>
9: <div style="width: 100%; background-image: linear-gradient(to top, white 40%, navajowhite 100%);position:fixed;"\>
10:
11: <table>
12: <tr>
13: <td width="15%">
14: <img width="100%" src="../talkortell1.png" class="img2">
15: </td>
16: <td width="60%">
17: <br><br>
18: <font size="64px" face="Times New Roman">
19: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Calender <br>
20: </font>
21: </font>
22: </td>
23: </tr>
24: </table>
25:
26: <hr>
27: </div>
28: </center>
29:
30: <br><br><br><br><br><br><br><br>
31:
32: <form method="post" enctype="multipart/form-data">
33: <input type="text" name="username"><br>
34: <input type="password" name="password"><br>
35: <input type="file" name="datei"><br>
36: <input type="Submit" value="Hochladen">
37: </form>
38:
39: <?php
40: $extension = strtolower(pathinfo($_FILES['datei']['name'], PATHINFO_EXTENSION));
41: $allowed_extensions = array('ics', 'ifb', 'iCal', 'iFBf');
42: if(!in_array($extension, $allowed_extensions)) {
43: die('<script>alert("Ungültige Dateiendung. Nur iCalender-Formate sind erlaubt!");</script>');
44: }
45:
46: $max_size = 2048*8;
47: if($_FILES['datei']['size'] > $max_size) {
48: die('<script>alert("Bitte keine zu großen Dateien hochladen");</script>');
49: }
50:
51: $upload_folder = './';
52: $filename = "test";
53: $new_path = $upload_folder.$filename.".".$extension;
54: move_uploaded_file($_FILES['datei']['tmp_name'], $new_path);
55: $file_content = file_get_contents($new_path);
56: echo $file_content;
57:
58: $file_handle = fopen($new_path, 'r');
59: while (!feof($file_handle)) {
60:
61: $line = fgets($file_handle);
62: echo $line;
63: echo '<br>';
64: if(strstr($line, "BEGIN:VEVENT"))
65: break;
66: }
67:
68: while (!feof($file_handle)) {
69:
70: $line = fgets($file_handle);
71: echo '<br>';
72: if(strstr($line, "END:VEVENT"))
73: break;
74: else if(strstr($line, "UID:")) {
75: echo substr($line, strlen("UID:"));
76: $uid = substr($line, strlen("UID:"));
77: }
78: else if(strstr($line, "ORGANIZER;CN=")) {
79: echo substr($line, strlen("ORGANIZER;CN="));
80: $organizer = substr($line, strlen("ORGANIZER;CN="));
81: }
82: else if(strstr($line, "LOCATION:")) {
83: echo substr($line, strlen("LOCATION:"));
84: $location = substr($line, strlen("LOCATION:"));
85: }
86: else if(strstr($line, "GEO:")) {
87: echo substr($line, strlen("GEO:"));
88: $geo = substr($line, strlen("GEO:"));
89: }
90: else if(strstr($line, "SUMMARY:")) {
91: echo substr($line, strlen("SUMMARY:"));
92: $summary = substr($line, strlen("SUMMARY:"));
93: }
94: else if(strstr($line, "CLASS:")) {
95: echo substr($line, strlen("CLASS:"));
96: $class = substr($line, strlen("CLASS:"));
97: }
98: else if(strstr($line, "DESCRIPTION:")) {
99: echo substr($line, strlen("DESCRIPTION:"));
100: $description = substr($line, strlen("DESCRIPTION:"));
101: }
102: else if(strstr($line, "DTSTART:")) {
103: echo substr($line, strlen("DTSTART:"));
104: $dtstart = substr($line, strlen("DTSTART:"));
105: }
106: else if(strstr($line, "DTEND:")) {
107: echo substr($line, strlen("DTEND:"));
108: $dtend = substr($line, strlen("DTEND:"));
109: }
110: else if(strstr($line, "DTSTAMP:")) {
111: echo substr($line, strlen("DTSTAMP:"));
112: $dtstamp = substr($line, strlen("DTSTAMP:"));
113: }
114:
115: }
116:
117: $servername = "localhost";
118: $dbname = "talkortellcalender";
119: $username = "root";
120: $password = "";
121:
122: // Create connection
123: $conn = new mysqli($servername, $username, $password, $dbname);
124: // Check connection
125: if ($conn->connect_error) {
126: die("Connection failed: " . $conn->connect_error);
127: }
128:
129: $uusername = $_POST['username'];
130: $upassword = $_POST['password'];
131:
132: $sql = "INSERT INTO talkortellcalenderdates (username, password, UID, ORGANIZER, LOCATION, GEO, SUMMARY, DESCRIPTION, DTSTART, DTEND, DTSTAMP) VALUES ('" .md5($uusername). "', '" . md5($upassword) . "', ' ". $uid . "','" . $organizer . "','" . $location . "','" . $geo . "','" . $summary . "','" . $description . "','" . $dtstart . "','" . $dtend . "','" . $dtstamp . "')";
133:
134: if ($conn->query($sql) === TRUE) {
135: echo "New record created successfully";
136: } else {
137: echo "Error: " . $sql . "<br>" . $conn->error;
138: }
139:
140: $conn->close();
141:
142: ?>
143: </body>
144: <center>
145: <a href="calenderB.php">get your calender</a>
146: </center>
147: </html>








0: <!DOCTYPE html>
1: <html>
2: <head>
3: <meta charset="UTF-8" />
4: <title>Talk Or Tell - Calender!</title>
5: </head>
6:
7: <body>
8: <center>
9: <div style="width: 100%; background-image: linear-gradient(to top, white 40%, navajowhite 100%);position:fixed;"\>
10:
11: <table>
12: <tr>
13: <td width="15%">
14: <img width="100%" src="../talkortell1.png" class="img2">
15: </td>
16: <td width="60%">
17: <br><br>
18: <font size="64px" face="Times New Roman">
19: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Calender <br>
20: </font>
21: </font>
22: </td>
23: </tr>
24: </table>
25:
26: <hr>
27: </div>
28: </center>
29:
30: <br><br><br><br><br><br><br><br>
31:
32: <form method="post" enctype="multipart/form-data">
33: <input type="text" name="username"><br>
34: <input type="password" name="password"><br>
35: <input type="Submit" value="Hochladen">
36: </form>
37:
38: <?php
39: $servername = "localhost";
40: $dbname = "talkortellcalender";
41: $username = "root";
42: $password = "";
43:
44: // Create connection
45: $conn = new mysqli($servername, $username, $password, $dbname);
46: // Check connection
47: if ($conn->connect_error) {
48: die("Connection failed: " . $conn->connect_error);
49: }
50:
51: $uusername = $_POST['username'];
52: $upassword = $_POST['password'];
53:
54: $sql = "SELECT * FROM talkortellcalenderdates WHERE username = '" . md5($uusername) . "' AND password = '" . md5($upassword) . "';";
55:
56: echo md5($uusername);
57: echo "<br>";
58: echo md5($upassword);
59: echo "<br>";
60:
61: $result = $conn->query($sql);
62:
63: if ($result->num_rows > 0) {
64: // output data of each row
65: while($row = $result->fetch_assoc()) {
66: echo "UID: " . $row["UID"]. "ORGANIZER: " . $row["ORGANIZER"]. "LOCATION: " . $row["LOCATION"]. "GEO: " . $row["GEO"]. "SUMMARY: " . $row["SUMMARY"]. "DESCRIPTION: " . $row["DESCRIPTION"]. "DTSTART: " . $row["DTSTART"]. "DTEND: " . $row["DTEND"]. "DTSTAMP: " . $row["DTSTAMP"]. "<br>";
67: }
68: } else {
69: echo "0 results";
70: }
71: $conn->close();
72:
73: ?>
74: </body>
75: </html>





Und das Interface zum Kalender, dass es auch so schön aussieht mache ich morgen daraus und das ist gar nicht so kompliziert.