Julian: Bilder in MySQL

Hallo,

ich möchte gerne bei einem auf MySQL basierendem CMS dem User die Möglichkeit geben, Bilder hochzuladen. Diese sollen dann in einer DB abgespeichert werden und dann, bei Bedarf, wieder abgerufen werden. Wie kann ich das machen?

Danke!

  1. Moin!

    ich möchte gerne bei einem auf MySQL basierendem CMS dem User die Möglichkeit geben, Bilder hochzuladen. Diese sollen dann in einer DB abgespeichert werden und dann, bei Bedarf, wieder abgerufen werden. Wie kann ich das machen?

    Ich würde die Bilder nicht in der Datenbank speichern, sondern als Datei auf Platte, und nur einen Verweis auf die Grafik in die Datenbank packen.

    - Sven Rautenberg

  2. Hallo,

    ich möchte gerne bei einem auf MySQL basierendem CMS dem User die Möglichkeit geben, Bilder hochzuladen. Diese sollen dann in einer DB abgespeichert werden und dann, bei Bedarf, wieder abgerufen werden. Wie kann ich das machen?

    Auch ich rate dazu, die Dateien in das Filesystem hochzuladen und nur die Namen der Bilder in der DB zu speichern.

    Ansonsten kannst Du Dir mal diesen Beispielcode ansehen:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    <title>Daten in DB schreiben</title>
    <meta name="Author" content="Dr. Thomas Meinike">
    <link rev="made" href="mailto:thomas@handmadecode.de">
    </head>
    <body>
    <?php
    if($action=="indb")
    {
    $dbref=mysql_connect("localhost", "...", "...");
    mysql_select_db("datenbank",$dbref) or die(mysql_errno() .": ". mysql_error());

    if(isset($datei) && $datei!="none")
    {
      $inhalt=addslashes(fread(fopen($datei,"r"),filesize($datei)));
      $dname=$HTTP_POST_FILES["datei"]["name"];
      $dgroesse=$HTTP_POST_FILES["datei"]["size"];
      $dtyp=$HTTP_POST_FILES["datei"]["type"];

    // Feld daten = LONGBLOB, alle weiteren VARCHAR
      $abfrage="INSERT INTO tabelle (daten,dname,dgroesse,dtyp) VALUES ('$inhalt','$dname','$dgroesse','$dtyp')";

    $ergebnis=mysql_query($abfrage,$dbref);

    if($ergebnis==1)
      {
        print "<b>Die Datei wurde in die DB übernommen:</b><br><br>\n";

    print "<i>Ausgabe über $HTTP_POST_FILES["datei"]["..."]</i><br>\n";
        print "Dateiname: ".$HTTP_POST_FILES["datei"]["name"]."<br>\n";
        print "Dateigröße: ".$HTTP_POST_FILES["datei"]["size"]." Bytes<br>\n";
        print "Dateityp: ".$HTTP_POST_FILES["datei"]["type"]."<br><br>\n";
      }
      else
      {
        print "<b>Die Daten konnten nicht in die DB übernommen werden.</b>\n";
      }
      mysql_close();
    }
    }
    else
    {
    ?>
    <form action="<?=$PHP_SELF;?>" method="post" enctype="multipart/form-data">
     <input type="hidden" name="MAX_FILE_SIZE" value="100000">
     <input type="hidden" name="action" value="indb">
     <input type="file" maxlength="100000" size="30" name="datei"><br>
     <input type="submit" value="In DB schreiben">
    </form>
    <?php
    }
    ?>
    </body>
    </html>

    Wichtig ist, den Dateityp mitzuspeichern, um beim Auslesen den richtigen Content-type senden zu koennen.

    MfG, Thomas

    1. Moin

      $inhalt=addslashes(fread(fopen($datei,"r"),filesize($datei)));
        $dname=$HTTP_POST_FILES["datei"]["name"];
        $dgroesse=$HTTP_POST_FILES["datei"]["size"];
        $dtyp=$HTTP_POST_FILES["datei"]["type"];

      öhm, warum verwendest du für die unwichtigen Daten die sicheren Methoden und für die wichtigen Daten die unsichere Methode?

      Wichtig ist, den Dateityp mitzuspeichern, um beim Auslesen den richtigen Content-type senden zu koennen.

      Viel wichtiger wäre es, beim Auslesen der Datei wenigstens ein bisschen auf die Sicherheit zu achten. So wie du es gemacht hast, kann jeder Hans Wurst jede für den Server lesbare Datei lesen.

      Daher solltest du lieber erstmal http://aktuell.de.selfhtml.org/artikel/phpasp/php-uploadcheck/index.htm lesen.

      --
      Henryk Plötz
      Grüße aus Berlin

      1. Hallo Henryk,

        Viel wichtiger wäre es, beim Auslesen der Datei wenigstens ein bisschen auf die Sicherheit zu achten. So wie du es gemacht hast, kann jeder Hans Wurst jede für den Server lesbare Datei lesen.

        Die Dateien sollten doch im upload_tmp_dir landen und wenn dieses außerhalb des doc_root liegt (wovon ich ausgehe), sollte doch niemand darauf zugreifen koennen, zumal die temporaere Datei automatisch wieder geloescht wird.

        Ansonsten war das eher ein (noch) lokales Testbeispiel. HTTP_POST_VARS["..."] kommen noch hinein, aber sonst sehe ich auch nach dem Lesen des genannten Artikels kein weiteres "Vergehen".

        MfG, Thomas

        1. Moin,

          Die Dateien sollten doch im upload_tmp_dir landen und wenn dieses außerhalb des doc_root liegt (wovon ich ausgehe), sollte doch niemand darauf zugreifen koennen, zumal die temporaere Datei automatisch wieder geloescht wird.

          Es geht darum dass du nicht mal im Ansatz überprüfst ob die Datei die in der Datenbank landet wirklich hochgeladen wurde (oder hab ich den supergenialen Trick der das bewerkstelligt übersehen?).
          Wenn ich nichts besseres zu tun hab, rufe ich das Skript mit skript.php?action=indb&datei=/etc/passwd auf und schon ist die Systempasswortdatei in der Datenbank und kann von dort aus evt. ausgelesen werden. Auf diese Art kann ich dann _jede_ Datei lesen, auf die der Webserver Zugriff hat. Das sind neben der interessanten Passwortdatenbank evt. auch Konfigurationsdateien der verwendeten Skripte mit den darin enthaltenen Passwörtern, etc.

          Nach dem erneuten lesen des Artikels (ist schon ein bisschen her, das ich das getan hab) gestehe ich aber, dass mein Hinweis nicht vollständig war. Die wichtigste Funktion die du benutzen möchtest wird in dem Artikel nämlich nicht erwähnt: http://www.php.net/manual/de/function.is-uploaded-file.php bzw. http://www.php.net/manual/de/function.move-uploaded-file.php.

          Wenn du wirklich noch ein PHP älter als 4.0.3 benutzen musst, musst du dir die Funktionen evt. noch mit HTTP_POST_FILES (http://www.php.net/manual/de/language.variables.predefined.php#language.variables.predefined.php) selbst bauen. Aber die Dateien in keiner Weise zu überprüfen, ist imho grob fahrlässig und solche gefährlichen Skripts sollte man nicht ohne Hinweis auf diese Gefahr posten.

          --
          Henryk Plötz
          Grüße aus Berlin

          1. Hallo,

            Nach dem erneuten lesen des Artikels (ist schon ein bisschen her, das ich das getan hab) gestehe ich aber, dass mein Hinweis nicht vollständig war. Die wichtigste Funktion die du benutzen möchtest wird in dem Artikel nämlich nicht erwähnt: http://www.php.net/manual/de/function.is-uploaded-file.php bzw. http://www.php.net/manual/de/function.move-uploaded-file.php.

            OK, danke, das ist hilfreich.

            MfG, Thomas

          2. Es geht darum dass du nicht mal im Ansatz überprüfst ob die Datei die in der Datenbank landet wirklich hochgeladen wurde (oder hab ich den supergenialen Trick der das bewerkstelligt übersehen?).
            Wenn ich nichts besseres zu tun hab, rufe ich das Skript mit skript.php?action=indb&datei=/etc/passwd auf und schon ist die Systempasswortdatei in der Datenbank und kann von dort aus evt. ausgelesen werden. Auf diese Art kann ich dann _jede_ Datei lesen, auf die der Webserver Zugriff hat. Das sind neben der interessanten Passwortdatenbank evt. auch Konfigurationsdateien der verwendeten Skripte mit den darin enthaltenen Passwörtern, etc.

            1. Wenn man die Datei öffnet, werden die Passwörter nich angezeigt
            2. Ist bei den Providern PHP so konfiguriert, dass man nur in einem bestimmten Pfad Dateien öffnen kann!

            Gruß

            1. Moin!

              1. Wenn man die Datei öffnet, werden die Passwörter nich angezeigt
              2. Ist bei den Providern PHP so konfiguriert, dass man nur in einem bestimmten Pfad Dateien öffnen kann!

              Aber nur, wenn der Provider das wirklich so gemacht hat. Das sind dann aber zusätzliche Schutzmechanismen, auf die man sich verläßt - muß ja nicht sein, die könnten ja auch versagen.

              - Sven Rautenberg

            2. Moin

              Wenn ich nichts besseres zu tun hab, rufe ich das Skript mit skript.php?action=indb&datei=/etc/passwd auf und schon ist die Systempasswortdatei in der Datenbank und kann von dort aus evt. ausgelesen werden. Auf diese Art kann ich dann _jede_ Datei lesen, auf die der Webserver Zugriff hat. Das sind neben der interessanten Passwortdatenbank evt. auch Konfigurationsdateien der verwendeten Skripte mit den darin enthaltenen Passwörtern, etc.

              1. Wenn man die Datei öffnet, werden die Passwörter nich angezeigt
              2. Ist bei den Providern PHP so konfiguriert, dass man nur in einem bestimmten Pfad Dateien öffnen kann!

              Wohl ein bisschen suizidal veranlagt, was?
              zu 1. Man tut die Datei sicher nicht in die Datenbank damit die Datenbank mal wieder was zu tun hat. In der einen oder anderen Form kommt der Inhalt auch wieder raus. Es kann sein, dass das dann nur an dich geht, muß aber nicht. In der Datenbank, die evt. über das Skript einsehbar ist, liegt die Datei jedenfalls viel unsicherer als im lokalen Dateisystem.

              zu 2. Öhöm, nicht wirklich.
              Ja, einige Provider haben PHP im CGI-Modus mit suid-wrappern laufen, so dass die Skripte nur die Dateien lesen können, die dir gehören. Trotzdem ist es sehr wahrscheinlich dass da auch die Konfigurations-Dateien deiner Skripte mit den Master- und/oder Datenbankpasswörtern, evt. die .htpasswd-Dateien sowie sonstige interessante Informationen drin sind. Wenn du schon an so einfachen Stellen wie der Überprüfung der Dateiuploads versagst, ist es wahrscheinlich, dass du noch mehr Sicherheitslücken eingebaut hast, so dass die Kenntnis der .php-Dateien auch sehr nützlich sein könnte, um diese auszunutzen.
              Ja, einige Provider lassen PHP im safe-mode laufen, was unter anderem dazu führt, dass Dateien nur aus einem bestimmten Verzeichnis geöffnet werden können. Und falls es nicht dazu führt, das das mit den Dateiuploads ohnehin nicht klaptt, so schützt es dich auch nicht davor deine eigenen Dateien zu lesen.

              Merkst du was? Nicht alle Provider machen das, und das ist gut so. Dein Skript sollte nicht kaputtgehen und böse Angriffe erlauben, bloss weil ein Provider andere Einstellungen hat, als ein anderer. Zumal die genannten Einstellungen nur bei Massenhostern halbwegs verbreitet sind.

              Wenn du glaubst, dass du dich über elementare Sicherheitsaspekte hinwegsetzen kannst, ist das dein Bier. Aber du und ich sind nicht die einzigen die den Thread hier lesen, also bitte vermittle denjenigen die noch nicht den vollen Durchblick haben, keine falschen Vorstellungen.

              Traurige Kapitel wie http://www.securityfocus.net/search?category=23&query=php+file kommen nicht einfach so aus dem nichts.

              --
              Henryk Plötz
              Grüße aus Berlin