Ulli: Datei in mysqlDatenbank ablegen, [BLOB - 0 B]

Ich möchte eine Datei in einer mysql Datenbank abspeichern.

if(is_uploaded_file ( $_FILES['formular_datei']['tmp_name'] ))
{
$datei_size=filesize($_FILES['formular_datei']['tmp_name']);
$datei=fopen($_FILES['formular_datei']['tmp_name'],'r');
$data=addslashes(fread( $datei, $datei_size));
$sql="INSERT INTO doku (datei) values ('$data')";	
$das_wars = mysql_query($sql);
}

Das Ergebniss ist leider in der Datenbank ein leeres Feld: [BLOB - 0 B]

was mache ich da falsch?

  1. Tach!

    was mache ich da falsch?

    Du verwendest addslashes(), was für MySQL zwar geeignet aber nicht vorgesehen ist.
    Du verwendest die veraltete mysql-Extension und nicht mysqli.
    Du betreibst kein Debugging, um zu erkennen, an welcher Stelle du von deinen Vorstellungen abweichende Werte bekommst. var_dump() kann helfen.
    Du fragst auch nicht ab, ob der MySQL-Aufruf erfolgreich war sowie eventuelle Fehlermeldungen.

    dedlfix.

  2. Hallo und guten Morgen,

    Ich möchte eine Datei in einer mysql Datenbank abspeichern.

    if(is_uploaded_file ( $_FILES['formular_datei']['tmp_name'] ))
    {
    $datei_size=filesize($_FILES['formular_datei']['tmp_name']);
    $datei=fopen($_FILES['formular_datei']['tmp_name'],'r');
    $data=addslashes(fread( $datei, $datei_size));
    $sql="INSERT INTO doku (datei) values ('$data')";	
    $das_wars = mysql_query($sql);
    }
    
    

    Das Ergebniss ist leider in der Datenbank ein leeres Feld: [BLOB - 0 B]

    was mache ich da falsch?

    Schau Dir mal den Unterschied zwischen addslashes() und mysqli_real_escape_string() an, welche Bytewerte ("Zeichen" wäre hier mMn nicht richtig) da escaped werden.

    Da Du die Datei über die Textschnittstelle von MySQL übergibst, die ja bekanntlich Daten und Befehle mischt, musst Du die Daten auch für diese Textschnittstelle vorbereiten, damit eben nicht einzelne Bytewerte dazu führen, dass die Textschnittstelle sie (und nachfolgende) als Befehl auffasst.

    Umgehen kannst Du das mit "prepared Statements". Dort werden die Werte vom Programm ins Statement eingebaut. Und das kümmert sich dann auch um das Escaping.

    Beim Hochladen von Dateien solltest Du auf jeden Fall darauf achten, dass diese auf dem Server nicht (ungeprüft) in einem per HTTP/s zugänglichen Pfad landen. Außerdem solltest Du keine von Usern vorgeschlagenen Dateinamen (ungeprüft) übernehmen. Besser ist immer ein auf dem Server generierter ungefährlicher Dateiname.

    Du würdest dir sonst eine Sciherheitslücke in deinen Server reißen. Es könnten Skripte dabei sein oder wichtige Dateien überschrieben werden.

    Grüße
    TS

    1. Tach!

      Schau Dir mal den Unterschied zwischen addslashes() und mysqli_real_escape_string() an, welche Bytewerte ("Zeichen" wäre hier mMn nicht richtig) da escaped werden.

      mysql(i)_real_escape_string() beachtet die mit mysql(i)_set_charset() ausgehandelte Kodierung (nicht aber ein SET-NAMES-Statement). Für die hierzulande verwendeten Kodierungen ISO-8859-x und UTF-8 ergibt sich aber hinsichtlich der Wirkungsweise keine Unterschied. Alle Zeichen liegen eineindeutig im überall gleichen ASCII-Bereich.

      Da Du die Datei über die Textschnittstelle von MySQL übergibst, die ja bekanntlich Daten und Befehle mischt, musst Du die Daten auch für diese Textschnittstelle vorbereiten, damit eben nicht einzelne Bytewerte dazu führen, dass die Textschnittstelle sie (und nachfolgende) als Befehl auffasst.

      Ist mit addslashes() prinzipiell ausreichend passiert. Die restlichen Zeichen, die die mysql(i)-Funktionen zusätzlich berücksichtigen, spielen in Statements keine Rolle.

      Umgehen kannst Du das mit "prepared Statements". Dort werden die Werte vom Programm ins Statement eingebaut. Und das kümmert sich dann auch um das Escaping.

      Nein, das kümmert sich nicht drum, das hat gar kein Escaping nötig.

      Beim Hochladen von Dateien solltest Du auf jeden Fall darauf achten, dass diese auf dem Server nicht (ungeprüft) in einem per HTTP/s zugänglichen Pfad landen. Außerdem solltest Du keine von Usern vorgeschlagenen Dateinamen (ungeprüft) übernehmen. Besser ist immer ein auf dem Server generierter ungefährlicher Dateiname.

      Dateinamen spielen in dem Fall keine Rolle, da der Dateiinhalt gleich in der Datenbank landet und der Name ein vom System selbst vergebener temporärer Name ist?

      Du würdest dir sonst eine Sciherheitslücke in deinen Server reißen. Es könnten Skripte dabei sein oder wichtige Dateien überschrieben werden.

      Ich seh zwar in dem gezeigten Code eine Menge Verbesserungspotenzial, aber keine Sicherheitslücke.

      dedlfix.

      1. Hallo und guten Morgen,

        Umgehen kannst Du das mit "prepared Statements". Dort werden die Werte vom Programm ins Statement eingebaut. Und das kümmert sich dann auch um das Escaping.

        Nein, das kümmert sich nicht drum, das hat gar kein Escaping nötig.

        Da will ich aber nochmal "hinten reingucken", was da wirklich passiert. Ist es nicht so, dass trotzdem ein SQL-Statement generiert wird?

        Grüße
        TS

        1. Tach!

          Da will ich aber nochmal "hinten reingucken", was da wirklich passiert. Ist es nicht so, dass trotzdem ein SQL-Statement generiert wird?

          Das kann dir als Nutzer egal sein, weil du darauf keinen Einfluss hast und sich in keinem Fall etwas ändert. Wenn es echte Prepared Statements sind, dann gehen das Statement und die Daten getrennte Wege, und das ist was zählt. Aber auch diesen Fakt muss man nicht zwangsläufig wissen. Man kann sich auch auf die Betrachtung der API beschränken. Schon da musst du Statement und Daten trennen und letztere in Rohform übergeben.

          dedlfix.

          1. Hallo und guten Morgen,

            Da will ich aber nochmal "hinten reingucken", was da wirklich passiert. Ist es nicht so, dass trotzdem ein SQL-Statement generiert wird?

            Das kann dir als Nutzer egal sein, weil du darauf keinen Einfluss hast und sich in keinem Fall etwas ändert. Wenn es echte Prepared Statements sind, dann gehen das Statement und die Daten getrennte Wege, und das ist was zählt. Aber auch diesen Fakt muss man nicht zwangsläufig wissen. Man kann sich auch auf die Betrachtung der API beschränken. Schon da musst du Statement und Daten trennen und letztere in Rohform übergeben.

            Ich hab ja vorhin auch nichts anderes beahuptet, als dass bei Verwendung von Prepared Statements sich das Programm um das Escaping kümmert (sofern es denn notwendig ist). Wenn in der API "Uses" benutzt wird, ist es duchaus noch notweindig, wenn Adressen auf Datenblöcke gehandelt werden, deren Typ und Größe bekannt sind, eben nicht. Dann kommt ja gar keine Text-/Befehlsschnittstelle mehr mit den Daten in Berührung.

            Grüße
            TS