Come posso fare Base64 codificare/decodificare un valore in Oracle?Base64 codifica e decodifica in oracolo
risposta
Ho implementato questo per inviare cirillici e-mail attraverso il mio server MS Exchange.
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;
Provalo.
UPD: dopo un aggiustamento minore sono arrivato fino a questo, in modo che funziona in entrambi i sensi ora:
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;
è possibile controllare:
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
UPD2: Ok, Ecco una conversione di esempio che funziona per CLOB
Mi è appena venuto in mente. Prova a risolverlo per i tuoi BLOB. :)
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
/*we substract pieces of substring_length*/
substring := dbms_lob.substr(clobOriginal,
least(substring_length, substring_length * n + 1 - length(clobOriginal)),
substring_length * n + 1);
/*if no substring is found - then we've reached the end of blob*/
if substring is null then
exit;
end if;
/*convert them to base64 encoding and stack it in new clob vadriable*/
clobInBase64 := clobInBase64 || to_base64(substring);
n := n + 1;
end loop;
n := 0;
clobOriginal := null;
/*then we do the very same thing backwards - decode base64*/
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;
/*and insert the data in our sample table - to ensure it's the same*/
insert into clobTable (id, anotherClobField) values (1, clobOriginal);
end;
http://psoug.org/reference/utl_encode.html controllo primi due
può u prego di dirmi come fare per il tipo di dati BLOB? Ricevo un'eccezione "Bugger Troppo piccolo per la conversione da CLOB a CHAR o da BLOB a RAW (effettivo 50176, massimo 2000)". – Pradeep
Scusa ... Ricevo un'eccezione "BufferToo small per la conversione da CLOB a CHAR o da BLOB a RAW (effettivo 50176, massimo 2000)". – Pradeep
oracle utl_raw pacchetto accetta solo input varchar2, che è breve, quindi immagino che tutto ciò che potresti fare sia dividere il tuo BLOB in blocchi più piccoli usando il pacchetto dbms_lob, quindi convertirli ciascuno usando il metodo che ho fornito, e poi rimetterli insieme indietro in un singolo blob. puoi dare un codice di errore che stai ricevendo, a proposito? –
Tutti i post precedenti sono corretti. C'è più di un modo per dare la pelle a un gatto. Ecco un altro modo per fare la stessa cosa: (basta sostituire "what_ever_you_want_to_convert" con la stringa ed eseguirlo in Oracle:
set serveroutput on;
DECLARE
v_str VARCHAR2(1000);
BEGIN
--Create encoded value
v_str := utl_encode.text_encode
('what_ever_you_want_to_convert','WE8ISO8859P1', UTL_ENCODE.BASE64);
dbms_output.put_line(v_str);
--Decode the value..
v_str := utl_encode.text_decode
(v_str,'WE8ISO8859P1', UTL_ENCODE.BASE64);
dbms_output.put_line(v_str);
END;
/
fare url_raw.cast_to_raw()
supporto in Oracle 6
Soluzione con utl_encode.base64_encode
e utl_encode.base64_decode
hanno una limitazione, funzionano solo con stringhe fino a 32.767 caratteri/byte.
Nel caso in cui si debbano convertire stringhe più grandi si dovranno affrontare diverse o bstacles.
- Per
BASE64_ENCODE
la funzione è di leggere 3 Bytes e trasformarli. In caso di caratteri Multi-Byte (ad esempioöäüè€
memorizzati in UTF-8, ovveroAL32UTF8
) 3 Il carattere non è necessariamente anche 3 Byte. Per leggere sempre 3 byte devi convertire il tuoCLOB
inBLOB
prima. - Lo stesso problema si applica a
BASE64_DECODE
. La funzione deve leggere 4 byte e trasformarli in 3 byte. Quei 3 Bytes non sono necessariamente anche 3 caratteri - Tipicamente un BASE64-String ha NEW_LINE (
CR
e/oLF
) carattere ciascuna 64 caratteri. Tali caratteri di nuova riga devono essere ignorati durante la decodifica.
Prendendo tutto questo in considerazione la soluzione piena funzionalità potrebbe essere questa:
CREATE OR REPLACE FUNCTION DecodeBASE64(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; -- must be a whole multiple of 4
buffer RAW(1440);
stringBuffer VARCHAR2(1440);
-- BASE64 characters are always simple ASCII. Thus you get never any Mulit-Byte character and having the same size as 'amount' is sufficient
BEGIN
IF InBase64Char IS NULL OR NVL(ClobLen, 0) = 0 THEN
RETURN NULL;
ELSIF ClobLen<= 32000 THEN
RETURN UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(InBase64Char)));
END IF;
-- UTL_ENCODE.BASE64_DECODE is limited to 32k, process in chunks if bigger
-- Remove all NEW_LINE from base64 string
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 DecodeBASE64;
CREATE OR REPLACE FUNCTION EncodeBASE64(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; -- must be a whole multiple of 3
-- size of a whole multiple of 48 is beneficial to get NEW_LINE after each 64 characters
buffer RAW(1440);
res CLOB := EMPTY_CLOB();
BEGIN
IF InClearChar IS NULL OR NVL(ClobLen, 0) = 0 THEN
RETURN NULL;
ELSIF ClobLen <= 24000 THEN
RETURN UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(InClearChar)));
END IF;
-- UTL_ENCODE.BASE64_ENCODE is limited to 32k/(3/4), process in chunks if bigger
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 EncodeBASE64;
funziona abbastanza bene per me anche se ottengo spazi nel mezzo della mia codifica. Inserisco uno spazio di espressione regolare in sostituzione del mio risultato e sono in affari: regexp_replace (utl_raw.cast_to_varchar2 (utl_encode.base64_encode (utl_raw.cast_to_raw (t))), '[[: space:]] *', '') – Kirby
C'è un piccolo bug nel secondo aggiornamento: il parametro "amount" del dbms_log.substr dovrebbe essere "least (substring_length, length (clobInBase64) - (substring_length * n + 1))". Il modo in cui lo hai scritto restituisce una quantità negativa, quindi la sottostringa è sempre vuota. – BernardMarx
La codifica BASE64 richiede 3 byte di flusso di input e la converte in 4 * 3 byte. Ognuno di questi 3 byte viene mappato su 64 caratteri diversi (a-z, A-Z, 0-9, "+", "/" - quindi si ottiene il nome BASE64). Assicurati che il valore di substring_length sia un multiplo intero di 4 per 'BASE64_DECODE', risp. un intero multiplo di 3 per 'BASE64_ENCODE'. Quindi la tua funzione 'to_base64' potrebbe restituire risultati errati. –