45 Stimmen

Base64-Codierung und -Dekodierung in Oracle

Wie kann ich einen Wert in Oracle in Base64 codieren/decodieren?

60voto

Kirill Leontev Punkte 10311

Ich habe dies implementiert, um kyrillische E-Mails über meinen MS Exchange Server zu senden.

function to_base64(t in varchar2) return varchar2 is
 begin
    return utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(t)));
end to_base64;

Probiere es aus.

aktualisiert: Nach einer kleinen Anpassung habe ich dies entwickelt, so dass es jetzt in beide Richtungen funktioniert:

function from_base64(t in varchar2) return varchar2 is
begin
  return utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(t)));
end from_base64;

Du kannst es überprüfen:

SQL> set serveroutput on
SQL> 
SQL> declare
  2    function to_base64(t in varchar2) return varchar2 is
  3    begin
  4      return utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(t)));
  5    end to_base64;
  6  
  7    function from_base64(t in varchar2) return varchar2 is
  8    begin
  9      return utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw    (t)));
 10    end from_base64;
 11  
 12  begin
 13    dbms_output.put_line(from_base64(to_base64('asdf')));
 14  end;
 15  /

asdf

PL/SQL procedure successfully completed

aktualisiert2: Ok, hier ist eine Beispielumwandlung, die für CLOB funktioniert, die ich gerade entwickelt habe. Versuche es für deine Blobs herauszufinden. :)

declare

  clobOriginal     clob;
  clobInBase64     clob;
  substring        varchar2(2000);
  n                pls_integer := 0;
  substring_length pls_integer := 2000;

  function to_base64(t in varchar2) return varchar2 is
  begin
    return utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(t)));
  end to_base64;

  function from_base64(t in varchar2) return varchar2 is
  begin
    return utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(t)));
  end from_base64;

begin

  select clobField into clobOriginal from clobTable where id = 1;

  while true loop

    /* wir subtrahieren Teile von substring_length */
    substring := dbms_lob.substr(clobOriginal,
                                 least(substring_length, substring_length * n + 1 - length(clobOriginal)),
                                 substring_length * n + 1);  
    /* wenn kein Unterteil gefunden wird - dann sind wir am Ende des Blobs angekommen */

    if substring is null then
      exit;
    end if;  

    /* konvertieren sie in Base64-Codierung und stapeln sie in einer neuen CLOB-Variablen */
    clobInBase64 := clobInBase64 || to_base64(substring);          
    n := n + 1;  

  end loop;

  n := 0;
  clobOriginal := null;

  /* dann machen wir genau dasselbe rückwärts - Base64 decodieren */
  while true loop 

    substring := dbms_lob.substr(clobInBase64,
                                 least(substring_length, substring_length * n + 1 - length(clobInBase64)),
                                 substring_length * n + 1);  
    if substring is null then
      exit;
    end if;  
    clobOriginal := clobOriginal || from_base64(substring);  
    n := n + 1;  
  end loop; 

      /* und fügen die Daten in unsere Beispieltabelle ein - um sicherzustellen, dass es gleich ist */
  insert into clobTable (id, anotherClobField) values (1, clobOriginal);

end;

14voto

Wernfried Domscheit Punkte 45772

Lösung mit utl_encode.base64_encode und utl_encode.base64_decode haben eine Einschränkung, sie funktionieren nur mit Zeichenfolgen von bis zu 32.767 Zeichen/Bytes.

Falls Sie größere Zeichenfolgen konvertieren müssen, werden Sie auf mehrere Hindernisse stoßen.

  • Für BASE64_ENCODE muss die Funktion 3 Bytes lesen und diese transformieren. Im Fall von Multi-Byte-Zeichen (z.B. öäüè€ gespeichert in UTF-8, auch bekannt als AL32UTF8) sind 3 Zeichen nicht unbedingt auch 3 Bytes. Um immer 3 Bytes zu lesen, müssen Sie Ihren CLOB zunächst in BLOB konvertieren.
  • Das gleiche Problem gilt für BASE64_DECODE. Die Funktion muss 4 Bytes lesen und sie in 3 Bytes umwandeln. Diese 3 Bytes sind nicht unbedingt auch 3 Zeichen
  • Typischerweise hat eine BASE64-Zeichenfolge nach jeweils 64 Zeichen einen NEW_LINE (CR und/oder LF) Zeichen. Solche Zeilenumbruchzeichen müssen beim Dekodieren ignoriert werden.

Unter Berücksichtigung all dessen könnte die vollständige Lösung folgende sein:

ERSTELLEN ODER ERSETZEN VON FUNKTION KurzBASE64Entschlüsseln(InBase64Char IN OUT NOCOPY CLOB) RETURN CLOB IS

    blob_loc BLOB;
    clob_trim CLOB;
    res CLOB;

    lang_context INTEGER := DBMS_LOB.DEFAULT_LANG_CTX;
    dest_offset INTEGER := 1;
    src_offset INTEGER := 1;
    read_offset INTEGER := 1;
    warning INTEGER;
    ClobLen INTEGER := DBMS_LOB.GETLENGTH(InBase64Char);

    amount INTEGER := 1440; -- muss ein vielfaches von 4 sein
    buffer RAW(1440);
    stringBuffer VARCHAR2(1440);
    -- BASE64-Zeichen sind immer einfaches ASCII. Daher gibt es niemals mehrere Zeichen und die gleiche Größe wie "Betrag" reicht aus

BEGIN

    FALLS InBase64Char IST NULL ODER NVL(ClobLen, 0) = 0 DANN 
        RETURN NULL;
    SONST FALLS ClobLen <= 32000 DANN
        RETURN UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(InBase64Char)));
    END IF;        
    -- UTL_ENCODE.BASE64_DECODE ist auf 32k begrenzt, verarbeiten in Blöcken bei größeren    

    -- Entfernen Sie alle NEW_LINE aus der Base64-Zeichenfolge
    ClobLen := DBMS_LOB.GETLENGTH(InBase64Char);
    DBMS_LOB.CREATETEMPORARY(clob_trim, TRUE);
    LOOP
        EXIT WHEN read_offset > ClobLen;
        stringBuffer := REPLACE(REPLACE(DBMS_LOB.SUBSTR(InBase64Char, amount, read_offset), CHR(13), NULL), CHR(10), NULL);
        DBMS_LOB.WRITEAPPEND(clob_trim, LENGTH(stringBuffer), stringBuffer);
        read_offset := read_offset + amount;
    END LOOP;

    read_offset := 1;
    ClobLen := DBMS_LOB.GETLENGTH(clob_trim);
    DBMS_LOB.CREATETEMPORARY(blob_loc, TRUE);
    LOOP
        EXIT WHEN read_offset > ClobLen;
        buffer := UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(DBMS_LOB.SUBSTR(clob_trim, amount, read_offset)));
        DBMS_LOB.WRITEAPPEND(blob_loc, DBMS_LOB.GETLENGTH(buffer), buffer);
        read_offset := read_offset + amount;
    END LOOP;

    DBMS_LOB.CREATETEMPORARY(res, TRUE);
    DBMS_LOB.CONVERTTOCLOB(res, blob_loc, DBMS_LOB.LOBMAXSIZE, dest_offset, src_offset,  DBMS_LOB.DEFAULT_CSID, lang_context, warning);

    DBMS_LOB.FREETEMPORARY(blob_loc);
    DBMS_LOB.FREETEMPORARY(clob_trim);
    RETURN res;    

END KurzBASE64Entschlüsseln;

ERSTELLEN ODER ERSETZEN VON FUNKTION KurzBASE64Verschlüsseln(InClearChar IN OUT NOCOPY CLOB) RETURN CLOB IS

    dest_lob BLOB;  
    lang_context INTEGER := DBMS_LOB.DEFAULT_LANG_CTX;
    dest_offset INTEGER := 1;
    src_offset INTEGER := 1;
    read_offset INTEGER := 1;
    warning INTEGER;
    ClobLen INTEGER := DBMS_LOB.GETLENGTH(InClearChar);

    amount INTEGER := 1440; -- muss ein vielfaches von 3 sein
    -- Größe eines ganzzahligen Vielfachen von 48 ist vorteilhaft, um NEW_LINE nach jedem 64. Zeichen zu erhalten 
    buffer RAW(1440);
    res CLOB := EMPTY_CLOB();

BEGIN

    FALLS InClearChar IST NULL ODER NVL(ClobLen, 0) = 0 DANN 
        RETURN NULL;
    SONST FALLS ClobLen <= 24000 DANN
        RETURN UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(InClearChar)));
    END IF;
    -- UTL_ENCODE.BASE64_ENCODE ist auf 32k/(3/4) begrenzt, verarbeiten in Blöcken bei größeren    

    DBMS_LOB.CREATETEMPORARY(dest_lob, TRUE);
    DBMS_LOB.CONVERTTOBLOB(dest_lob, InClearChar, DBMS_LOB.LOBMAXSIZE, dest_offset, src_offset, DBMS_LOB.DEFAULT_CSID, lang_context, warning);
    LOOP
        EXIT WHEN read_offset >= dest_offset;
        DBMS_LOB.READ(dest_lob, amount, read_offset, buffer);
        res := res || UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(buffer));       
        read_offset := read_offset + amount;
    END LOOP;
    DBMS_LOB.FREETEMPORARY(dest_lob);
    RETURN res;

END KurzBASE64Verschlüsseln;

2voto

grepit Punkte 18534

Alle vorherigen Beiträge sind korrekt. Es gibt mehr als einen Weg, eine Katze zu häuten. Hier ist ein anderer Weg, um dasselbe zu tun: (ersetzen Sie einfach "what_ever_you_want_to_convert" durch Ihren String und führen Sie ihn in Oracle aus:

    set serveroutput on;
    DECLARE
    v_str VARCHAR2(1000);
    BEGIN
    --Erstellen Sie den codierten Wert
    v_str := utl_encode.text_encode
    ('what_ever_you_want_to_convert','WE8ISO8859P1', UTL_ENCODE.BASE64);
    dbms_output.put_line(v_str);
    --Dekodieren des Werts..
    v_str := utl_encode.text_decode
    (v_str,'WE8ISO8859P1', UTL_ENCODE.BASE64);
    dbms_output.put_line(v_str);
    END;
    /

Quelle

-5voto

vikas Punkte 1

Unterstützt url_raw.cast_to_raw() in Oracle 6?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X