Jak mogę dokonać kodowania/dekodowania wartości Base64 w Oracle?Kodowanie i dekodowanie Base64 w wyroczni
Odpowiedz
I zostały wdrożone to, aby wysłać e-maile cyrylicy przez mojego serwera 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;
Wypróbuj.
UPD: po niewielkiej korekcie wpadłem na to, więc to działa w obie strony teraz:
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;
Można go sprawdzić:
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, Oto przykładowa konwersja, która działa dla CLOB
Po prostu wymyśliłem. Postaraj się opracować dla swoich plam. :)
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 najpierw sprawdzić dwa
może u proszę mi powiedzieć jak to zrobić dla danych typu BLOB? Otrzymuję wyjątek "Bugger Too small for CLOB to CHAR lub BLOB to RAW conversion (actual 50176, maximum 2000)". – Pradeep
Przepraszam ... Otrzymuję wyjątek "BufferToo mały dla konwersji CLOB na CHAR lub BLOB na RAW (rzeczywisty 50176, maksymalnie 2000)". – Pradeep
Pakiet oracle utl_raw akceptuje tylko wejście varchar2, które jest krótkie, więc domyślam się, że wszystko co możesz zrobić, to podzielić swój obiekt blob na mniejsze części za pomocą pakietu dbms_lob, a następnie przekonwertować każdy z nich za pomocą dostarczonej przeze mnie metody, a następnie skleić je razem w pojedynczym bloku. możesz przy okazji podać kod błędu, który otrzymujesz? –
Wszystkie poprzednie posty są poprawne. Jest więcej niż jeden sposób na skórze kota. Oto kolejny sposób, aby zrobić to samo: (tylko zastąpić "what_ever_you_want_to_convert" z łańcucha i uruchomić go w 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;
/
zrobić url_raw.cast_to_raw()
wsparcie w oracle 6
rozwiązanie z utl_encode.base64_encode
i utl_encode.base64_decode
mają jedno ograniczenie, działają tylko z ciągami o długości do 32 767 znaków/bajtów. bstacles.
- Dla
BASE64_ENCODE
funkcja musi czytać 3 Bytes i przekształcić je. W przypadku znaków wielobajtowych (np.öäüè€
przechowywanych w UTF-8, akaAL32UTF8
) 3 Znak niekoniecznie są również 3 Bajty. Aby odczytać zawsze 3 bajty, musisz najpierw przekonwertować swójCLOB
naBLOB
. - Ten sam problem dotyczy
BASE64_DECODE
. Funkcja musi odczytać 4 bajty i przekształcić je na 3 bajty. Bajty te 3 niekoniecznie są również 3 Postacie - Zazwyczaj base64 String NEW_LINE (
CR
i/lubLF
) postać co 64 znaków. Takie znaki nowej linii muszą być ignorowane podczas dekodowania.
Biorąc to wszystko pod uwagę pełne rozwiązanie funkcjonalny może być to jedno:
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;
działa całkiem dobrze dla mnie, mimo że dostaję spacje w środku mojego kodowania. Wstawiam przestrzeń wyrażenia regularnego wokół mojego wyniku i działam: regexp_replace (utl_raw.cast_to_varchar2 (utl_encode.base64_encode (utl_raw.cast_to_raw (t))), [[: space:]] * ',' ') – Kirby
Występuje mały błąd w drugiej aktualizacji: Parametr "amount" dla dbms_log.substr powinien być "najmniejszy (substring_length, length (clobInBase64) - (substring_length * n + 1))". Sposób, w jaki został napisany, zwraca wartość ujemną, więc podciąg jest zawsze pusty. – BernardMarx
Kodowanie BASE64 pobiera 3 bajty strumienia wejściowego i konwertuje je na 4 * 3 bajty. Każdy z tych 3 Bajtów jest odwzorowany na 64 różne znaki (a-z, A-Z, 0-9, "+", "/" - stąd otrzymujesz nazwę BASE64). Upewnij się, że wartość substring_length jest wielokrotnością 4 dla 'BASE64_DECODE', resp. cała wielokrotność 3 dla 'BASE64_ENCODE'. Zatem funkcja 'to_base64' może zwrócić nieprawidłowy wynik. –