Wie kann ich einen Wert in Oracle in Base64 codieren/decodieren?
Antworten
Zu viele Anzeigen?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;
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 alsAL32UTF8
) sind 3 Zeichen nicht unbedingt auch 3 Bytes. Um immer 3 Bytes zu lesen, müssen Sie IhrenCLOB
zunächst inBLOB
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/oderLF
) 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;
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;
/