Announcement

Collapse
No announcement yet.

Problem beim stückweise Speichern von base64-Daten in MSSQL

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem beim stückweise Speichern von base64-Daten in MSSQL

    Hallo !

    Ich habe ein kleines Problem beim Speichern binärer Daten in einer MSSQL-Datenbank.
    Aufgabenstellung ist es .pdf- bzw .doc dateien binär in der Datenbank abzulegen.
    Hierzu habe ich folgenden Code geschrieben (vereinfacht):

    Code:
    // File wird geöffnet und Inhalt in Variable gespeichert
    $fh = $fopen("pdfdokument.pdf","rb");
    $filedata = fread($fh, filesize("pdfdokument.pdf")+1);
    
    // File wird in base64 codiert um ihn mit der SQL-Query auszuführen
    $base64data = base64_encode($filedata);
    
    // File in Datenbank speichern
    $sql = "INSERT INTO files (data) VALUES (CONVERT(varbinary(max),CONVERT(varchar(max),$base64data))";
    $res = mssql_query($sql);
    Das funktioniert soweit einwandfrei, die Daten lassen sich auch problemlos auslesen und wieder als Datei (mit entsprechendem MIME-Type) anzeigen.

    Problem:
    Die zu speichernden Dateien können manchmal auch relativ groß sein (3-10MB), was dazu führt das PHP das Script mit dem FATAL ERROR: allowed memory size exhausted abbricht.
    Pfiffig wie ich bin ;-) war mein Lösungsansatz für dieses Problem die Dateien nicht auf einmal in die Datenbank zu schreiben, sondern sie stückweise einzulesen.
    Alles wunderbar, das Script wird nicht mehr abgebrochen und Daten werden in die Datenbank geschrieben.
    Allerdings werden die Daten bei diesem Vorgang zerstört bzw verändert, so das ich sie nicht mehr korrekt auslesen kann.
    Ich kann aber den Fehler der zur fehlerhaften Speicherung führt nicht lokalisieren.
    Zum einen könnte ich mir vorstellen, dass MSSQL die binären Daten beim Speichern anpasst und es beim verketten mit den neuen Daten zu einem Fehler kommt. (i.d.R wird der zuerst eingefügte teil korrekt ausgegeben) Und auch die hin und her Konvertierung der Daten ist natürlich eine Fehlerquelle.
    Zum Anderen könnte ich mir auch vorstellen, dass die _gesonderte Codierung_ der einzelnen Teilstrings in base64 die Daten die letzendlich in der Datenbank stehen verändert.
    Hier der Code der die Daten in die Datenbank schreibt(wieder Beispielcode der Einfachheit halber):

    Code:
    $filesize = filesize("pdffile.pdf");
    $temp_filesize = $filesize/4;
    
    $i = 0;
    while(!feof($fh))
    {
      $filedata = fread($fh,$temp_filesize+1);
      $base64data = base64_encode($filedata);
      if($i==0){
        $sql = "INSERT INTO files (data) VALUES ( CONVERT(varbinary(max), CONVERT(varchar(max),'$base64data')) ); SELECT @@identity AS last_id";
        // Abfrage und Ergebnistest
        $id = $row['last_id'];
      }
      else{
        $sql = "UPDATE files SET data=CONVERT(varbinary(max), CONVERT(varchar(max),data)+CONVERT(varchar(max),'$base64data')) WHERE id=$id";
        // Abfrage und Ergebnistest
      }
      $i++;
    }
    Wenn ich nun die Daten ausgebe sind sie zerstört, dh. die Rückgabedaten weichen von den Eingabedaten ab.
    Meine Frage ist nun:
    Hat jemand eine Idee was für zur Veränderung der Daten führt?
    (Vielleicht sind es ja auch mehre Fehlerquellen)
    Mein persönlicher Eindruck ist das die Daten durch die stückweise Codierung mit base64 verändert werden. Aber warum? Und wie kann ich diesen Fehler beheben/ausgleichen?

    Ergänzung:
    Code:
    -- testtabelle
    CREATE TABLE(
      id int IDENTITY(1,1),
      data varbinary(max),
      CONSTRAINT pk PRIMARY KEY (id)
    );
    PS: mir ist durchaus bewußt, dass man Files nicht in die Datenbank steckt, aber mein "Kunde" akzeptiert nur diese Lösung. Mir wär es auch lieber die Daten im Filesystem abzulegen. Also bitte ich euch nur das hier beschriebene Problem zu diskutieren - insofern das jemand möchte ;-)

    Schon mal im Voraus Danke für eure Hilfe!

  • #2
    Hallo dionysois,

    die Lösung deines Problems liegt mit Sicherheit im Verständnis der Base64 Kodierung. Base64 macht aus einem 8Bit-Code einen 7Bit-Code. Dabei ist es natürlich nicht egal, ob du eine Datei am Stück kodierst oder in mehreren Teilstücken. Will heißen wenn du einen 100Byte String nimmst, diesen Base64 kodierst, dann ist das Ergebnis nicht das Gleiche wenn du den String in zwei 50Byte Teile teilst, diese Base64 kodierst und beide Teilergebnisse wieder zusammenhängst. Diese Teilkodierung und Verkettung liefert mit Sicherheit beim dekodieren keine gültigen Daten - max. der erste Teil wird stimmen. Aber das hast du ja schon gemerkt
    Du mußt die kodierten Teilstücke auch als Teilstücke wieder dekodieren und darfst erst die dekodierten Daten wieder als Binary zusammensetzen.
    Mein Vorschlag: Du erweiterst dein Tabellenmodell um die Möglichkeit das eine Datei aus mehreren DS bestehen kann. Dann speicherst du jedes kodierte Teilstück als separaten DS ab. Beim Auslesen genau andersherum: jeden DS auslesen, dekodieren und die (dekodierten) Ergebnisse zusammensetzen.

    Gruß Falk
    Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

    Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

    Comment

    Working...
    X