ashbury: cgi und Datenbank

Hi, ich verwende bisher erfolgreich und sehr gerne cgi basierte Formulare. Die Daten der html Formulare werden mir somit als Email zugesendet und dem Benutzer ebenfalls. Frage: ist es grundsätzlich möglich - ohne viel Aufwand -, dass diese Formulardaten in eine Datenbank (mysql) eingelesen werden?
Gruß and alle!

  1. Hallo ashbury,

    Grundsätzlich JA!

    Ohne Informationen zur verwendeten Programmiersprache lässt sich aber nicht viel mehr dazu sagen.

    Zum Beispiel in Perl:
    CPAN-Module DBI und DBD::mysql.

    Gruß
    Helmut Weber

    --
    -------------------------------------------
    Mode ist eine Variable, Stil eine Konstante
    1. Hallo Helmut,

      könnte ich Dir mal ein einfaches Skript von mir schicken und Du sagst mir obs und wies geht!?! Das wäre supi!
      Danke und Gruß, Marc

      Hallo ashbury,

      Grundsätzlich JA!

      Ohne Informationen zur verwendeten Programmiersprache lässt sich aber nicht viel mehr dazu sagen.

      Zum Beispiel in Perl:
      CPAN-Module DBI und DBD::mysql.

      Gruß
      Helmut Weber

      1. Hallo Marc,

        könnte ich Dir mal ein einfaches Skript von mir schicken und Du sagst mir obs und wies geht!?! Das wäre supi!

        Lass uns Dein Problem doch hier im Forum lösen, dann haben evtl. auch Andere etwas davon ;)
        Eine ausführliche Dokumentation zum DBI-Modul findest Du im CPAN unter:
        http://search.cpan.org/~timb/DBI-1.48/DBI.pm

        Du kannst die relevanten Code-Abschnitte deines Skriptes mit den dazugehörigen Fehlermeldungen gerne hier im Forum posten, oder bei langen Skripten diese hier verlinken.
        Ich bin sicher, dass die Gemeinschaft des Forums Dir schneller und effektiver helfen kann als ich alleine!

        Gruß
        Helmut Weber

        --
        -------------------------------------------
        Mode ist eine Variable, Stil eine Konstante
        1. Hi nochmal, also hier das Skript, welches z.Zt. gut läuft. Es fehlt eben eine SQL Anbindung, damit die Daten 001-016 eingelesen werden können.

          #! /usr/local/bin/perl

          Ein Perlskript, das Formulareingaben auswertet und als Mail weiterschickt.

          print "Content-type: text/html\n\n";
          $mailprog="/usr/lib/sendmail";
          %daten=&Eingabe;
          %datum=&zeit;
          $parameter = &Formateingaben(%daten);

          E-Mail des Urhebers

          $empfaenger="test@test.de";

          Formularfelder, die angegeben werden müssen (Pflichtfelder)

          if (!$daten{'001 Kongressgebühr'}) { &fehler("Kongressgebühr"); }
          if (!$daten{'002 Anrede'}) { &fehler("Anrede"); }
          if (!$daten{'004 Vorname'}) { &fehler("Vorname"); }
          if (!$daten{'005 Name'}) { &fehler("Name"); }
          if (!$daten{'009 PLZ'}) { &fehler("PLZ"); }
          if (!$daten{'010 Ort'}) { &fehler("Ort"); }
          if (!$daten{'011 Bundesland'}) { &fehler("Bundesland"); }
          if (!$daten{'012 Telefon'}) { &fehler("Telefon"); }
          if (!$daten{'014 E-Mail'}) { &fehler("E-Mail"); }

          E-Mail an Urheber sobald sich jemand angemeldet hat.

          open (MAIL, "|$mailprog $empfaenger") || die "Kann Mailprogramm in $mailprog nicht finden: $! \n";
          print MAIL "From: $daten{'014 E-Mail'} ($daten{'004 Vorname'} $daten{'005 Name'})\n";
          print MAIL "Reply-To: $daten{'014 E-Mail'}\n";
          print MAIL "To: $empfaenger\n";
          print MAIL "Subject: Anmeldung zum Kongress\n\n";
          print MAIL "Hallo, ich bin der automatische Formularauswerter.\n\n";
          print MAIL "Am $datum{'datum'} um $datum{'uhr'} hat sich ein Teilnehmer in das Anmeldeformular eingetragen. Nachfolgend die Daten:\n\n";
          print MAIL "001 Kongressgebühr: $daten{'001 Kongressgebühr'}\n";
          print MAIL "002 Anrede: $daten{'002 Anrede'}\n";
          print MAIL "003 Titel: $daten{'003 Titel'}\n";
          print MAIL "004 Vorname: $daten{'004 Vorname'}\n";
          print MAIL "005 Name: $daten{'005 Name'}\n";
          print MAIL "006 Institution: $daten{'006 Institution'}\n";
          print MAIL "007 Strasse: $daten{'007 Strasse'}\n";
          print MAIL "008 Hausnummer: $daten{'008 Hausnummer'}\n";
          print MAIL "009 PLZ: $daten{'009 PLZ'}\n";
          print MAIL "010 Ort: $daten{'010 Ort'}\n";
          print MAIL "011 Bundesland: $daten{'011 Bundesland'}\n";
          print MAIL "012 Telefon: $daten{'012 Telefon'}\n";
          print MAIL "013 Fax: $daten{'013 Fax'}\n";
          print MAIL "014 E-Mail: $daten{'014 E-Mail'}\n";
          print MAIL "015 Homepage: $daten{'015 Homepage'}\n";
          print MAIL "016 Info: $daten{'016 Info'}\n";
          close (MAIL);

          E-Mail an Kunden sobald dieser sich angemeldet hat.

          open (MAIL, "|$mailprog $daten{'014 E-Mail'}") || die "Kann Mailprogramm in $mailprog nicht finden: $! \n";
          print MAIL "From: $empfaenger\n";
          print MAIL "Reply-To: $empfaenger\n";
          print MAIL "To: $daten{'014 E-Mail'}\n";
          print MAIL "Subject: Ihre Anmeldung zum Kongress\n\n";
          print MAIL "Hiermit bestätigen wir Ihnen die Anmeldung.\n\n";
          print MAIL "Am $datum{'datum'} um $datum{'uhr'} haben Sie das Anmeldeformular ausgefüllt.\n";
          print MAIL "Nachfolgend Ihre Anmeldedaten:\n\n";
          print MAIL "001 Kongressgebühr: $daten{'001 Kongressgebühr'}\n";
          print MAIL "002 Anrede: $daten{'002 Anrede'}\n";
          print MAIL "003 Titel: $daten{'003 Titel'}\n";
          print MAIL "004 Vorname: $daten{'004 Vorname'}\n";
          print MAIL "005 Name: $daten{'005 Name'}\n";
          print MAIL "006 Institution: $daten{'006 Institution'}\n";
          print MAIL "007 Strasse: $daten{'007 Strasse'}\n";
          print MAIL "008 Hausnummer: $daten{'008 Hausnummer'}\n";
          print MAIL "009 PLZ: $daten{'009 PLZ'}\n";
          print MAIL "010 Ort: $daten{'010 Ort'}\n";
          print MAIL "011 Bundesland: $daten{'011 Bundesland'}\n";
          print MAIL "012 Telefon: $daten{'012 Telefon'}\n";
          print MAIL "013 Fax: $daten{'013 Fax'}\n";
          print MAIL "014 E-Mail: $daten{'014 E-Mail'}\n";
          print MAIL "015 Homepage: $daten{'015 Homepage'}\n";
          print MAIL "016 Info: $daten{'016 Info'}\n";
          close (MAIL);

          Rückgabe des HTML-Dokumentes mit Dank zur Anmeldung und Formulardatenauflistung

          my (@x)=split(/\n/,$parameter);
          foreach $i (@x)
          {
          ($k,$v)=split(/: /,$i);
          $str.="<td align=right>$k</td><td align=left>$v</td><tr>\n" if $k;
          }

          print <<EOF;
          <html>
          <head>
          <title>Kongress</title>
          </head>
          <body bgcolor=eff3f5>
          <table cellpadding="10">
          <td>
          <font size=3 face=ARIAL>Wir bedanken uns f&uuml;r Ihre Anmeldung.</font><br>
          <br>
          <table>
          <td align=left width="569"><font color=000000 face=ARIAL><font size=+1>Ihr Formular wurde abgeschickt.</font><br>
          <font size=3 face=ARIAL><font color=#000000>Sollten Sie &Auml;nderungen vornehmen wollen,k&ouml;nnen Sie die &quot;Zur&uuml;ck/BACK-Schaltfl&auml;che&quot; Ihres Browsers oder den <a href="javascript:history.back()" target="_self">zur&uuml;ck</a> Link nutzen.<br>
          Als Best&auml;tigung erhalten Sie eine E-Mail von uns mit den hier angegebenen Daten. Gleichzeitig k&ouml;nnen Sie diese Seite auch <a href="javascript:self.print()">ausdrucken</a>.<br>
          </font></td>
          </table>
          <br>
          <div align="center">
          <font size=3 face=ARIAL>Folgende Daten haben Sie in das Formular eingetragen:<br>
          <table width="573" table cellpadding="4" border=1 align="left" bgcolor=#c1ced7>
          $str
          <tr>
          <td> </td>
          </tr>
          </table>
          </body></HTML>

          EOF

          Hier endet der Hauptteil des Programms. Was folgt, sind die Subroutinen:

          sub Formateingaben
          {
          local (*in) = @_ if @_ == 1;
          local (%in) = @_ if @_ > 1;
          local ($out, $key, $output);

          $output =  "\n\n";
          foreach $key (sort keys(%in))
          {
            foreach (split("\0", $in{$key}))
            {
             ($out = $_) =~ s/\n/\n/g;
             $output .= "$key: $out\n";
              }
             }
          $output .=  "\n";

          return $output;
          }
          sub Eingabe
          {
          if ($ENV{'QUERY_STRING'})
          {
            $daten=$ENV{'QUERY_STRING'};
          } else
          { read (STDIN, $daten, $ENV{'CONTENT_LENGTH'}); }
          if (@ARGV) { @datensaetze=@ARGV; } else {
          @datensaetze = split(/&/, $daten); }
          foreach $satz (@datensaetze)
          {
            ($name, $wert) = split(/=/, $satz);
            $wert =~ tr/+/ /;
            $wert =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
            $wert =~ s/<(([^ >]|\n)*)>//g;
            $name =~ tr/+/ /;
            $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
            chomp $wert;
            $wert=~s/\n/<br>/g;
            $FORM{$name} = $wert;
          }
          return %FORM;
          }

          sub fehler
          {

          Diese Routine gibt eine Fehlermeldung aus, wenn ein wichtiges Formularfeld nicht ausgefüllt wurde

          my $fehler_grund=$_[0];
          print "<p><center><table border=5>\n";
          print "<td bgcolor=#c1ced7 align=center width=440><h1><font color=#ff3060><u></u></font></h1>";
          print "<font color=#000000><font size=+1>- Sie haben ein wichtiges Feld nicht ausgefüllt -</font><p>";
          print "Drücken Sie die Zurück/BACK-Schaltfläche Ihres Browsers oder den <a href='javascript:history.back()' target=_self>zurück</a></font> Link und vervollständigen bzw. korrigieren ";
          print "Sie das Feld<br> <font color=#ff3060><strong>$fehler_grund</strong></font>.<br><br>";
          print "</table>";
          exit;
          }

          sub zeit

          {
          local(@z)=localtime;
          foreach $i (@z) { if (length($i)<2) { $i="0".$i; } }
          local(%azeit);
          local($uhr)="$z[2]:$z[1]:$z[0]";
          local($monat)=($z[4]+1);
          if (length($monat)<2) { $monat="0".$monat; }

          $z[5]="19".$z[5];

          $z[5]=(1900+$z[5]);
          local($datum)="$z[3].$monat.$z[5]";
          $azeit{'uhr'}=$uhr;
          $azeit{'datum'}=$datum;
          return %azeit;
          }

          1. Hallo Marc,

            Dein Skript liest Formulardaten ein, verschickt diese per E-Mail und stellt diese per HTML auf dem Browser dar.

            Soweit waren wir ja schon ;)

            Jetzt nehm ich mal an, dass Du die Daten dauerhaft speichern möchtest. Bevor Du Dir Gedanken über eine Datenbank machst, musst Du überlegen, für welchen Zweck Du die Daten dauerhaft speichern möchtest. Evtl. ist es viel Einfacher die Daten in einer Textdatei zu speichern, um diese später wieder auszulesen.

            Solltest Du nach dieser Überlegung zum Entschluss kommen, Du benötigst unbedingt eine Datenbank, so musst Du Dir um folgende Dinge Gedanken machen:

            • welches DBMS?
            • Datenstruktur

            Dann musst Du Dir deine Datenbank und die Datentabellen einrichten, und erst dann geht es an die programmtechnische Umsetzung.

            Diese Arbeiten kann bzw. möchte ich Dir nicht abnehmen. Wenn Du mir in einem Skriptbeispiel zeigts, wie Du versucht hast die Daten in eine Datenbank anzulegen, dann kann ich Dir helfen den Fehler zu finden. Aber die Grundgedanken musst Du schon selbst erarbeiten.

            Gruß
            Helmut Weber

            --
            -------------------------------------------
            Mode ist eine Variable, Stil eine Konstante
            1. Hallo Helmut, danke für Deine Antwort. Ich hatte Dich zunächst falsch verstanden. Selbstverständlich hatte ich schon versucht, eine Datenbankanbindung zu erreichen. Bisher ohne Erfolg. Aber zunächst zum grundsätzlichen:

              • die Daten sollen in eine Datenbank, da sämtliche Daten später weiter in Datenbankform verarbeitet werden (nicht von mir, sondern von anderen). Eine Textdatei ist also nicht gewünscht.

              Ich habe einmal ein ganz einfaches Beispiel erzeugt:

              • html Formular mit nur einem (Pflicht)feld (Kongressgebühr)
              • sql Datenbank auf dem Server (db_test) mit einer Tabelle (test) und einer Tabellenzeile (Kongressgebühr)
              • perlskript, welches Pflichtfeld (Kongressgebühr) in die Datenbankzeile (Kongressgebühr) einfügen soll (die Option der Emailantwort etc habe ich weggelassen).

              Eine Fehlermeldung erhalte ich immerhin nicht, wenn ich das ganze auf meinem Server teste, trotzdem enden die Daten nicht in der Tabelle auf dem Server.

              Vielleicht kannst Du nochmal das jetzige Skript begutachten. Der relevante teil ist wohl #Datenbank Anbindung. Vielen Dank! marc

              Das ganze sieht dann so aus:

              #! /usr/local/bin/perl

              Ein Perlskript, das Formulareingaben auswertet.

              print "Content-type: text/html\n\n";
              $mailprog="/usr/lib/sendmail";
              %daten=&Eingabe;
              %datum=&zeit;
              $parameter = &Formateingaben(%daten);

              Formularfelder, die angegeben werden müssen (Pflichtfelder)

              if (!$daten{'Kongressgebühr'}) { &fehler("Kongressgebühr"); }

              Datenbank Anbindung: hier soll versucht werden die Werte des Pflichtfeld 'Kongressgebühr' in eine Datenbank einzulesen.

              Die SQL Datenbank ist 'db_test', die relevante Tabelle 'test' und die Zelle 'Kongressgebühr'. Die Eingaben des Nutzers in das html Feld 'Kongressgebühr' sollen also in die Tabelle eingelesen werden.

              use CGI;
              use DBI;
              my $DB_NAME = "db_test";
              my $DB_DSN = "DBI:mysql:database=$DB_NAME";
              my $DB_USER = "User_test";
              my $DB_PASSWD = "Passwort_test";
              my $dbh = DBI->connect($DB_DSN, $DB_USER, $DB_PASSWD) or die "Fehler bei Datenbankverbindung: $!";

              my $sql = "INSERT INTO test VALUES ('$daten')";
              my $sth = $dbh->prepare( $sql ) ||
                   die "Kann Statement nicht vorbereiten: $DBI::errstr\n";

              $dbh->disconnect;

              Rückgabe des HTML-Dokumentes mit Dank zur Anmeldung und Formulardatenauflistung

              my (@x)=split(/\n/,$parameter);
              foreach $i (@x)
              {
              ($k,$v)=split(/: /,$i);
              $str.="<td align=right>$k</td><td align=left>$v</td><tr>\n" if $k;
              }

              print <<EOF;
              <html>
              <head>
              <title>Kongress</title>
              </head>
              <body bgcolor=eff3f5>
              <table cellpadding="10">
              <td>
              <font size=3 face=ARIAL>Wir bedanken uns f&uuml;r Ihre Anmeldung.</font><br>
              <br>
              <table>
              <td align=left width="569"><font color=000000 face=ARIAL><font size=+1>Ihr Formular wurde abgeschickt.</font><br>
              </table>
              <br>
              <div align="center">
              <font size=3 face=ARIAL>Folgende Daten haben Sie in das Formular eingetragen:<br>
              <table width="573" table cellpadding="4" border=1 align="left" bgcolor=#c1ced7>
              $str
              <tr>
              <td> </td>
              </tr>
              </table>
              </body></HTML>

              EOF

              Hier endet der Hauptteil des Programms. Was folgt, sind die Subroutinen:

              sub Formateingaben
              {
              local (*in) = @_ if @_ == 1;
              local (%in) = @_ if @_ > 1;
              local ($out, $key, $output);

              $output =  "\n\n";
              foreach $key (sort keys(%in))
              {
                foreach (split("\0", $in{$key}))
                {
                 ($out = $_) =~ s/\n/\n/g;
                 $output .= "$key: $out\n";
                  }
                 }
              $output .=  "\n";

              return $output;
              }
              sub Eingabe
              {
              if ($ENV{'QUERY_STRING'})
              {
                $daten=$ENV{'QUERY_STRING'};
              } else
              { read (STDIN, $daten, $ENV{'CONTENT_LENGTH'}); }
              if (@ARGV) { @datensaetze=@ARGV; } else {
              @datensaetze = split(/&/, $daten); }
              foreach $satz (@datensaetze)
              {
                ($name, $wert) = split(/=/, $satz);
                $wert =~ tr/+/ /;
                $wert =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
                $wert =~ s/<(([^ >]|\n)*)>//g;
                $name =~ tr/+/ /;
                $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
                chomp $wert;
                $wert=~s/\n/<br>/g;
                $FORM{$name} = $wert;
              }
              return %FORM;
              }

              sub fehler
              {

              Diese Routine gibt eine Fehlermeldung aus, wenn ein wichtiges Formularfeld nicht ausgefüllt wurde

              my $fehler_grund=$_[0];
              print "<p><center><table border=5>\n";
              print "<td bgcolor=#c1ced7 align=center width=440><h1><font color=#ff3060><u></u></font></h1>";
              print "<font color=#000000><font size=+1>- Sie haben ein wichtiges Feld nicht ausgefüllt -</font><p>";
              print "</table>";
              exit;
              }

              sub zeit

              {
              local(@z)=localtime;
              foreach $i (@z) { if (length($i)<2) { $i="0".$i; } }
              local(%azeit);
              local($uhr)="$z[2]:$z[1]:$z[0]";
              local($monat)=($z[4]+1);
              if (length($monat)<2) { $monat="0".$monat; }

              $z[5]="19".$z[5];

              $z[5]=(1900+$z[5]);
              local($datum)="$z[3].$monat.$z[5]";
              $azeit{'uhr'}=$uhr;
              $azeit{'datum'}=$datum;
              return %azeit;
              }

              1. Hallo Marc,

                Okay, das sieht ja schon viel besser aus ;)

                my $sql = "INSERT INTO test VALUES ('$daten')";
                my $sth = $dbh->prepare( $sql ) ||
                     die "Kann Statement nicht vorbereiten: $DBI::errstr\n";
                $dbh->disconnect;

                Ein INSERT-Befehl bei SQL brauch immer ein Feld/Wert-Paar, um zu wissen, welchen Wert in welches Feld zu schreiben ist.
                In deinem Fall:
                "INSERT INTO test ('Kongressgebühr') VALUES ('". $daten{'001 Kongressgebühr'}. "')"
                Hierbei ist noch anzumerken, dass es sicherer ist, auf Groß-/Kleinschreibung und auf Umlaute bzw. Sonderzeichen in den Bezeichnungen von Feldern, Variablen und Übergabewerte zu verzichten. Dies gilt für Datenbanken, Programmiersprachen und HTML-Formulare. Diese Angaben können nämlich von System zu System anderst interpertiert werden, und können Probleme verusrachen.

                Wenn Du später deine Tabelle erweitern möchtest, musst Du auch deine SQL-Anweisung anpassen:
                "INSERT INTO test ('feld1', 'feld2') VALUES ('daten1', 'daten2')"

                Bis hierhin hat das DBI-Modul deine SQL-Anweisung nur vorbereitet, jedoch noch nicht ausgeführt. Um deine INSERT-Anweisung nun auch auszuführen muss nach dem "prepare" ein "execute" erfolgen:
                $sth->execute();

                Oder in deinem Fall die einfachere Lösung, Du fasst beide Schritte in einer Anweisung zusammen:
                my $sth = $dbh->do( $sql ) ||
                     die "Kann Statement nicht vorbereiten: $DBI::errstr\n";

                Noch ein paar Tipps zu deinem Programm:

                • Nutze folgende Anweisung am Beginn deines Skriptes, um Dir Fehlermeldungen deines Skriptes am Browser ausgeben zu lassen:
                  use CGI::Carp qw( fatalsToBrowser );
                • Da Du schon das CGI-Modul in deinem Skript einbindest, solltest Du auch die Funktionen dieses Modules zum Auslesen der Formulardaten verwenden. Das macht dein Programm Übersichtlicher.
                • Das Modul Mail::Mailer kann Dir beim versenden von E-Mails evtl. eine Hilfe sein.
                • Das Modul HTML::Template bietet Dir die Möglichkeit HTML vom Programmcode zu trennen. Dies ist bei größeren Projekten auf jeden Fall hilfreich.

                Hoffe Dir geholfen zu haben, und stehe bei weiteren Fragen natürlich Rde und Antwort ;)

                Gruß
                Helmut Weber

                --
                -------------------------------------------
                Mode ist eine Variable, Stil eine Konstante
                1. Hi Helmut,

                  vielen Dank für Deine Hilfe. Jetzt hat es zumindest einmal geklappt Daten in eine SQL Tabelle zu schreiben. Mehr wollte ich auch gar nicht.
                  Noch eine kleine Frage ist aufgekommen: in der perl Datei, die auf meinem Server in einem Verzeichnis liegt, sind ja nun das Passwort und der Zugriff auf die Datenbank gespeichert. Kann diese Datei nicht von außen eingelesen werden? Oder wie kann man sich vor Mißbrauch schützen? Die Datei hat ja 755 Rechte.
                  Danke und Gruß, Marc

                  1. Hallo Marc,

                    vielen Dank für Deine Hilfe. Jetzt hat es zumindest einmal geklappt Daten in eine SQL Tabelle zu schreiben. Mehr wollte ich auch gar nicht.

                    Schön das es jetzt funktioniert ;)

                    Noch eine kleine Frage ist aufgekommen: in der perl Datei, die auf meinem Server in einem Verzeichnis liegt, sind ja nun das Passwort und der Zugriff auf die Datenbank gespeichert. Kann diese Datei nicht von außen eingelesen werden? Oder wie kann man sich vor Mißbrauch schützen? Die Datei hat ja 755 Rechte.

                    Der Webserver ist normalerweise so konfiguriert, das er Datein mit der Endung .pl oder .cgi nicht an den Browser zurück gibt, sondern durch den Perl-Kompiler jagt.
                    Wenn nun aus irgendeinem Grund eine falsche Konfiguration des Webservers erfolgt, kann es vorkommen, dass der Webserver die Datein, anstatt durch den Kompiler zu jagen, diese im Klartext an den Browser ausgibt (Was schon vorgekommen ist!).
                    Jetzt sind die Zugangsdaten zu deiner Datenbank natürlich einsehbar. Wenn Du Dich also nicht nur auf die Konfiguration des Webserver verlassen möchtest, gibt es auch die Möglichkeit die geheimen Daten in eine externe Datei auszulagern, und diese außerhalb des Zugriffbereiches des Webserver abzulegen.

                    Gruß
                    Helmut Weber

                    --
                    -------------------------------------------
                    Mode ist eine Variable, Stil eine Konstante