Você tem que lidar com o formato Base64? Então esse site é perfeito para você! Use o nosso ferramenta online super útil para codificar ou decodificar os seus dados.

Codificação Base64 em Perl: um guia completo

Você tem dados que precisam sobreviver a um canal que não gosta deles. Um blob binário que precisa morar num campo JSON. Uma imagem que tem que viver dentro de uma tag HTML. Um certificado que pertence a um arquivo de configuração. Um token que vai viajar por URLs, cabeçalhos e strings de query. Essa é a vida diária da codificação Base64: ela reescreve cada três bytes de dados crus como quatro caracteres de um alfabeto de 64 letras, com um ou dois sinais de = finalizando o rabo, para que o resultado seja texto simples que qualquer coisa pode carregar, tipicamente ficando uns 33 por cento mais longo do que a origem. A página inicial deste site explica o formato em profundidade, então este artigo foca no que o Perl te dá, no que ele decide em silêncio por você e em onde estão as armadilhas.

A boa notícia primeiro: o encode_base64 mora no core do Perl desde 2002, é implementado em C e é confortavelmente rápido. A parte interessante é que a função tem opiniões. Ela quebra a saída em 76 caracteres, anexa uma quebra de linha no final e não codifica caracteres Unicode que você não converteu em bytes antes: acima da faixa Latin-1 ela morre na hora, e abaixo dessa linha ela assume em silêncio bytes Latin-1. Este guia percorre cada sabor de Base64 que um desenvolvedor Perl realmente produz: o one-liner, o corpo de e-mail quebrado em MIME, a chave quebrada em PEM, o token URL-safe e a versão em streaming para arquivos grandes demais para caber em memória.

Uma função, uma quebra de linha escondida

A API inteira, exatamente como a documentação moderna apresenta:

encode_base64( $bytes )
encode_base64( $bytes, $eol )

Leia de novo. Dois argumentos, um deles opcional, um valor de retorno, sem flags. O segundo argumento opcional é a sequência de fim de linha, e o padrão é uma quebra de linha simples, o que significa que a chamada mais inocente do Perl produz saída com quebra de linha e terminada em newline:

use MIME::Base64 qw(encode_base64);
my $wrapped = encode_base64("Aladdin:open sesame");
print length($wrapped), "\n";  # 29: os 28 caracteres mais um newline
my $single = encode_base64("Aladdin:open sesame", "");
print length($single), "\n";   # 28: passe uma string vazia para não quebrar linhas

O tamanho da saída segue um padrão fixo que você pode prever antes de chamar:

Bytes de entrada Caracteres de saída Padding
0 0 nenhum
1 4 dois =
2 4 um =
3 4 nenhum
100,000 133,336 nenhum, em uma linha só
3,000,000 4,000,000 nenhum

O padrão é quatro caracteres para cada grupo completo de três bytes, mais um grupo final incompleto completado com um ou dois sinais de =. Uma consequência que vale conhecer: um byte e três bytes produzem, nos dois casos, quatro caracteres, então o tamanho codificado esconde o tamanho exato da entrada. E se você precisa do tamanho sem fazer o trabalho, o módulo tem uma função de tamanho desde o 3.10 em 2010. Ela só não é exportada por padrão, então você chama ela pelo nome do pacote:

use MIME::Base64 ();
my $with_wrap   = MIME::Base64::encoded_base64_length($bytes);        # linhas de 76 caracteres, eol padrão
my $single_line = MIME::Base64::encoded_base64_length($bytes, "");    # sem quebra de linha
my $mime_body   = MIME::Base64::encoded_base64_length($bytes, "\r\n");

Há mais uma regra para memorizar, porque é o único jeito que o codificador grita: se a string que você entrega contém caracteres com código acima de 255, o encode_base64 morre com Wide character in subroutine entry. Abaixo dessa linha a falha é mais quieta: caracteres até 255 são rebaixados em silêncio para os bytes Latin-1 deles, então uma string de caracteres acentuados que pulou a conversão é codificada como Latin-1 em vez de UTF-8, e ninguém te avisa. A codificação Base64 só está definida para caracteres de um byte, e o Perl 5.8 e superiores permitem caracteres estendidos em strings, então a conversão é uma decisão que você toma de propósito, com o Encode, na próxima seção.

Texto ou bytes? A etapa que a função não faz

Strings do Perl carregam uma flag discreta que diz se elas seguram caracteres ou bytes, e o Base64 mora do lado dos bytes nessa linha. Se o seu texto é uma string de caracteres, e é o momento em que ele vem de um parser JSON, de um template ou de um literal com letras acentuadas num arquivo de fonte UTF-8, o codificador recusa adivinhar que bytes você quis para caracteres acima da faixa Latin-1, e te avisa; abaixo da faixa ele adivinha Latin-1 em silêncio. A correção é a mesma nos dois casos, e é uma função core do módulo Encode:

use MIME::Base64 qw(encode_base64);
use Encode qw(encode);
my $chars = "H\x{eb}llo W\x{f6}rld";  # uma string de caracteres
my $utf8  = encode("UTF-8", $chars);  # agora: bytes
my $b64   = encode_base64($utf8, "");
print $b64, "\n";  # SMOrbGxvIFfDtnJsZA==

Aquela chamada de encode é a dança inteira: escolha a representação em bytes, e UTF-8 para qualquer coisa moderna, converta os caracteres para aqueles bytes, e só então entregue os bytes ao codificador. Para texto ocidental legado que chegou como Windows 1252, a conversão é a mesma função com um nome diferente, encode("Windows-1252", $legacy), que te entrega a forma original de um byte. O módulo Encode é core, então tudo isso não custa nada.

Agora a armadilha. Se os bytes que você tem já são UTF-8 e você passa eles por um encode("UTF-8", ...) de novo, pensando que está deixando eles UTF-8, você não ganha uma cópia: você ganha uma codificação dupla, onde cada caractere acentuado incha para virar dois caracteres por conta própria. O sintoma clássico é texto que antes lia Hëllo e agora lê Hëllo, e qualquer decodificador da internet vai decodificar aquilo com fidelidade para você:

use Encode qw(encode decode);
my $right = encode("UTF-8", "H\x{eb}llo");
my $wrong = encode("UTF-8", $right);  # re-codificando os bytes como caracteres
print decode("UTF-8", $right), "\n";  # Hëllo
print decode("UTF-8", $wrong), "\n";  # Hëllo

A regra prática que previne: bytes são codificados exatamente uma vez, e o utf8::is_utf8() te mostra de qual lado da linha uma string está. Se a flag está definida, você segura caracteres e a chamada encode() é a jogada certa; se não está definida, você segura bytes e está pronto para o Base64.

Quebra de linha: três dialetos, uma regra

Como a saída padrão é quebrada e terminada em newline, a primeira decisão de todo trabalho de codificação é um problema de destino: onde essa string vai morar? O fato unificador é que decodificadores ignoram quebras de linha por completo: a RFC 2045 manda o software de decodificação ignorar todas as quebras de linha e os caracteres fora do alfabeto, então a quebra de linha é uma cortesia para ferramentas baseadas em linhas e humanos, não uma diferença semântica. As três respostas na prática:

Sem quebras de linha. A saída da função com a quebra de linha desligada, exatamente uma linha. É isso que você quer para URLs, payloads JSON, cabeçalhos, valores de banco de dados e qualquer outra coisa onde uma quebra de linha seria um bug. É também o que a maioria das pessoas quer dizer quando pede só o Base64:

my $single = encode_base64($bytes, "");

MIME: 76 caracteres mais CRLF. A convenção de e-mail da RFC 2045: linhas codificadas não podem passar de 76 caracteres, e o mundo MIME fala CRLF. Essa é função do próprio módulo, feita com o segundo argumento:

my $mime_body = encode_base64($bytes, "\r\n");

PEM: 64 caracteres mais LF. Chaves e certificados usam a convenção mais antiga com linhas menores de 64 caracteres, e o módulo não produz essa largura sozinho, então um helper de quatro linhas preenche a lacuna:

sub wrap_lines {
  my ($text, $width) = @_;
  return join "\n", $text =~ /(.{1,$width})/g;
}
my $pem = "-----BEGIN CERTIFICATE-----\n"
        . wrap_lines(encode_base64($der, ""), 64) . "\n"
        . "-----END CERTIFICATE-----\n";

O mesmo helper serve para os outros dialetos de 64 caracteres - a codificação textual PKIX da RFC 7468 e a armadura OpenPGP, cujas linhas de dados têm 64 caracteres de largura e cuja linha de checksum CRC24 no final o GnuPG adiciona, não você. Uma pegadinha se aplica a todos: o encode_base64 anexa o fim de linha no final exato do resultado, mesmo quando a última linha enche a largura exata. Se um consumidor a jusante tropeçar nessa linha em branco no final, uma chamada de rtrim no resultado resolve.

Base64 URL-safe: o alfabeto do - e do _

O alfabeto padrão inclui o + e o /, e os dois são problema fora de um arquivo de texto: um + numa string de query codificada em formulário vira um espaço antes da sua aplicação ver, e o / é um separador de caminho em URLs. Nomes de arquivo e tokens têm as próprias reclamações. A RFC 4648, seção 5, resolve isso com o alfabeto seguro para URL e nome de arquivo, onde o + vira -, o / vira _ e o padding de = no final geralmente é descartado. A RFC insiste que isso não deve ser considerado a mesma coisa que a codificação base64, então trate como um formato distinto, comumente chamado de base64url. O Perl produz em uma única chamada desde a versão 3.11 em 2010:

use MIME::Base64 qw(encode_base64url);
my $seg = encode_base64url("sunset-42");
print $seg, "\n";  # c3Vuc2V0LTQy: sem padding, sem newline

Essa chamada única faz as três mudanças: a troca de alfabeto, sem padding, sem quebras de linha. Se você já segura Base64 padrão e o destino quer o dialeto URL-safe, duas operações de string convertem no lugar:

sub to_urlsafe {
  my ($b64) = @_;
  $b64 =~ tr{+/}{-_};
  return $b64 =~ s/=+\z//r;
}
my $seg = to_urlsafe(encode_base64($bytes, ""));

Quando usar: partes de JSON Web Token, parâmetros state e nonce do OAuth, IDs de API que você coloca em caminhos de URL, e chaves opacas que precisam sobreviver a uma barra de endereço ou a um nome de arquivo, onde o Data::UUID::Base64URLSafe do CPAN existe exatamente para isso. Quando não usar: corpos de e-mail, armadura PEM e qualquer lugar onde um consumidor de alfabeto padrão está do outro lado, porque - e _ não estão no vocabulário deles. E não misture os dois alfabetos em silêncio: um valor codificado URL-safe deve ser decodificado URL-safe, em todo lugar, para sempre. Em Perls anteriores ao 3.11, o módulo standalone MIME::Base64::URLSafe de 2006, que é um port do codec urlsafe do Python, fornece o urlsafe_b64encode; em qualquer coisa moderna, a função embutida é a ferramenta certa.

Montando um JWT: cada parte na mão

JSON Web Tokens são o consumidor principal do Base64 em APIs modernas, e eles usam o dialeto URL-safe, sem padding, da seção acima. Segundo a RFC 7515, um JWT compacto é três partes base64url separadas por pontos: o cabeçalho protegido, o payload e a assinatura. Montar um na mão é um jeito agradável de ver cada peça móvel:

use MIME::Base64 qw(encode_base64url);
use JSON::PP qw(encode_json);
use Digest::SHA qw(hmac_sha256);
my $secret  = "correct-horse-battery-staple";
my $head    = encode_base64url(encode_json({ alg => "HS256", typ => "JWT" }));
my $claims  = encode_base64url(encode_json({ sub => "homer", role => "admin" }));
my $sig     = encode_base64url(hmac_sha256("$head.$claims", $secret));
my $jwt     = "$head.$claims.$sig";
print $jwt, "\n";  # um token HS256 compacto; a ordem das chaves dentro de cada parte JSON varia de execução em execução

Três detalhes que valem notar. Primeiro, o encode_json do módulo JSON::PP do core emite bytes UTF-8 compactos sem espaços, que é exatamente o que as specs JOSE querem dentro de um token. Segundo, o payload é legível por qualquer um, e é por design: um JWT é um ticket assinado, não um segredo, então nunca coloque valores confidenciais nos claims. Terceiro, a assinatura é a codificação base64url de bytes HMAC crus, e é por isso que o hmac_sha256 vai direto para o codificador sem qualquer formatação hexadecimal.

Em produção, você não faz assinatura na mão. O módulo do CPAN Crypt::JWT, que se constrói sobre o CryptX, implementa JWS e JWE com o conjunto completo de algoritmos:

use Crypt::JWT qw(encode_jwt);
my $jwt = encode_jwt(
  payload => { sub => "homer", role => "admin" },
  alg     => "HS256",
  key     => $secret,
);

E no lado receptor, fixe o algoritmo com accepted_alg para que um atacante não consiga virar o token para uma variante mais fraca: decode_jwt(token => $jwt, key => $secret, accepted_alg => "HS256") verifica a assinatura e croaks em caso de falha. Fazer na mão é bom para entender; uma biblioteca é boa para dinheiro.

HTTP: cabeçalhos de autenticação, data URIs e o handshake WebSocket

O cabeçalho Authorization: Basic é o caso de uso vivo mais antigo: o nome de usuário e a senha unidos por dois-pontos, codificados em uma linha só, prefixados com a palavra do esquema. O segundo argumento de string vazia é portador de carga aqui, porque um newline no final dentro de um campo de cabeçalho é um bug:

use MIME::Base64 qw(encode_base64);
my $user = "alice";
my $pass = "s3cr3t";
my $header = "Basic " . encode_base64("$user:$pass", "");
print $header, "\n";  # Basic YWxpY2U6czNjcjN0

Data URIs da RFC 2397 são a mesma ideia aplicada a imagens: o payload mora direto na URL, então não precisa de um segundo pedido para buscá-lo. Mídias binárias usam a flag ;base64, então o payload é exatamente o que o encode_base64 produziu com a quebra de linha desligada:

my $uri = "data:" . $mime_type . ";base64," . encode_base64($bytes, "");

Os compromissos são reais, porém. O payload codificado fica uns 33 por cento maior que o arquivo, o que deixa o próprio documento HTML maior. Navegadores não fazem cache de uma data URI do jeito que fazem com a URL de um arquivo - não existe um fetch separado para fazer cache, então cada visualização de página despacha os bytes de novo como parte do documento, e a própria RFC diz que data URIs só são úteis para valores curtos. Use para avatares, ícones e gráficos inline pequenos; use arquivos de verdade para tudo o resto. Há um terceiro canto do HTTP que usa Base64 em silêncio: o handshake WebSocket da RFC 6455, onde o cliente envia um cabeçalho Sec-WebSocket-Key que é o Base64 de dezesseis bytes aleatórios. Frameworks como o Mojolicious fazem isso por você, mas se você um dia vir isso no fio, agora você sabe o que é:

use MIME::Base64 qw(encode_base64);
my $key = encode_base64(pack("C16", map { int(rand 256) } 1 .. 16), "");
print length($key), "\n";  # 24: dezesseis bytes aleatórios, completados até o grupo de quatro caracteres

Arquivos: slurps, chunks de 57 bytes e a CLI

O trabalho de codificação mais direto: um arquivo vira texto. Strings do Perl são bytes, então não existe modo binário para procurar - a camada :raw é a coisa inteira. Abra raw, leia, codifique, escreva:

use MIME::Base64 qw(encode_base64);
open my $in, "<:raw", $ARGV[0] or die $!;
local $/;
my $bytes = <$in>;
close $in;
open my $out, ">:raw", $ARGV[1] or die $!;
print {$out} encode_base64($bytes);
close $out;

As camadas :raw importam. Sem elas, o Perl tentaria interpretar os bytes como texto da plataforma na entrada e na saída, e num sistema com uma codificação padrão diferente aquilo é exatamente a corrupção que você não vê até o arquivo ser aberto em outro lugar. E lembre da conta de tamanho quando planejar armazenamento: uma imagem de 500 KB vira um arquivo de texto de 670 KB, e um vídeo de 1 GB vira 1.33 GB.

Para arquivos grandes demais para caber em memória, a documentação própria do módulo te dá a regra: codifique em chunks que são múltiplos de 57 bytes, porque 57 bytes de dados enchem exatamente uma linha de 76 caracteres, 76 sendo 57 vezes 4 dividido por 3. Faça chunks nessa fronteira e você nunca ganha padding no meio do stream:

use MIME::Base64 qw(encode_base64);
open my $in, "<:raw", $ARGV[0] or die $!;
while (read($in, my $buf, 57 * 10)) {
  print encode_base64($buf);
}
close $in;

Cada chunk cai exatamente nas fronteiras de linha, o último, possivelmente curto, chunk carrega o padding final, e o resultado é byte a byte o mesmo que devorar o arquivo inteiro e codificar de uma vez, só que com pegada de memória constante. E quando você não precisa de script nenhum, o one-liner cobre, com o -0777 devorando a entrada e o argumento de string vazia mantendo a saída em uma linha:

perl -MMIME::Base64 -0777 -ne 'print encode_base64($_, "")' < file > file.b64

E-mail: corpos MIME e anexos

E-mail é onde o Base64 ganhou o nome. O padrão MIME diz que dados que não podem viajar com segurança como texto cru devem ser enviados com Content-Transfer-Encoding: base64, em linhas de no máximo 76 caracteres. Se você monta e-mail com MIME::Lite, a coisa toda é um argumento, e o módulo faz a codificação, a quebra de linha e o cabeçalho por você:

use MIME::Lite;
my $mime = MIME::Lite->new(
  From    => 'me@example.com',
  To      => 'you@example.com',
  Subject => 'A file',
  Type    => 'text/plain',
  Data    => 'The body text.',
);
$mime->attach(
  Type     => 'application/octet-stream',
  Data     => $bytes,
  Encoding => 'base64',
  Filename => 'hello.txt',
);

O argumento Encoding é o gatilho: o MIME::Lite codifica o anexo em Base64 em linhas de 76 caracteres (com o newline simples padrão do módulo; é o transporte de e-mail que os transforma em CRLF) e carimba a parte com o cabeçalho Content-Transfer-Encoding correspondente. O Email::MIME adota a mesma posição e codifica em Base64 qualquer anexo que você entregar como string de dados crus (a documentação dele: "todas as partes criadas nesse estilo são codificadas com base64, só para o caso"). Se você está montando uma mensagem MIME crua na mão, o equivalente são as duas linhas da seção de envolvimento, encode_base64($bytes, "\r\n") mais a linha de cabeçalho, e essa é a história inteira do lado do protocolo.

Bancos de dados, config e variáveis de ambiente

Bancos de dados: dados binários frequentemente viajam numa coluna TEXT como Base64, porque a coluna não pode prometer que deixa bytes arbitrários passarem intactos. Guarde a forma em uma linha, nunca a quebrada, ou o seu próximo SELECT vai devolver uma string com newlines no meio do valor:

use MIME::Base64 qw(encode_base64);
# $dbh é um handle DBI já conectado
my $stmt = $dbh->prepare(q{UPDATE photos SET data = ? WHERE id = ?});
$stmt->execute(encode_base64($bytes, ""), 42);

Arquivos de configuração têm a mesma forma: um documento JSON onde o campo binário ou secreto é uma string Base64 em uma linha só, e é exatamente por isso que o segundo argumento existe:

use JSON::PP qw(encode_json);
my $config = {
  api_key  => encode_base64($key_bytes, ""),
  logo_png => encode_base64($png_bytes, ""),
};
open my $fh, ">:raw", "app.json" or die $!;
print {$fh} encode_json($config);
close $fh;

Variáveis de ambiente merecem uma palavra de aviso. Base64 é bom para tokens pequenos no ambiente, mas a forma codificada fica 33 por cento maior que o original, e o sistema operacional limita cada argumento. No Linux o limite é 128 KB por string, imposto pelo execve, e um blob grande numa variável de ambiente não falha com educação: o processo filho morre com um erro obscuro no momento em que é criado. Valores pequenos no ambiente, valores grandes num arquivo ou num banco de dados.

Performance: quem faz o trabalho é o C, não o Perl

O módulo core é implementado em C, e esse C descende de código escrito para o metamail em 1991, o que é um fato curioso até você notar a implicação: o codificador tem três décadas de ajuste. Numa máquina moderna ele processa dados a um ritmo de gigabytes por segundo, que é mais rápido que o disco ou a rede que ele normalmente está alimentando, então o próprio Base64 quase nunca é o gargalo. O I/O é.

Para o sistema raro sem compilador C, o gêmeo puro em Perl, MIME::Base64::Perl, no CPAN, oferece a mesma interface básica, algumas vezes mais lento, mas ainda confortável para cargas de trabalho comuns. E dois hábitos mantêm os trabalhos grandes previsíveis: faça stream com chunks de 57 bytes em vez de devorar, e dimensione seus buffers com encoded_base64_length antes de alocar, o que te poupa tanto o chute quanto a realocação.

Armadilhas, ranqueadas pelo custo da tarde

As armadilhas, mais ou menos na ordem em que mordem:

Armadilha O que acontece Correção
Esquecer o segundo argumento a saída chega quebrada em 76 caracteres com um newline no final, e a sua URL, campo JSON ou cabeçalho quebra no meio do valor passe "" para saída em uma linha, e mantenha a quebra de linha para destinos que esperam
Quebrar com a largura errada um consumidor PEM espera linhas de 64 caracteres e ganha 76, ou um corpo MIME passa do limite de 76 caracteres combine a largura com o dialeto: "" para nenhum, "\r\n" para MIME, um helper para PEM
O croak de caractere largo uma string de caracteres com códigos acima de 255 morre com Wide character in subroutine entry no meio do pedido passa os caracteres pelo Encode primeiro, nomeado de propósito, antes da chamada encode_base64
Codificação dupla re-codificar bytes que já são UTF-8 através de encode("UTF-8", ...) transforma Hëllo em Hëllo bytes são codificados exatamente uma vez; confira utf8::is_utf8() na dúvida
Misturar alfabetos em silêncio um valor codificado com - e _ bate num decodificador de alfabeto padrão e volta como lixo um dialeto por valor, de ponta a ponta: escolha base64url ou padrão na fronteira
O fim de linha no final encode_base64 anexa o eol mesmo quando a última linha está exatamente cheia, e um consumidor estrito vê uma linha em branco chomp ou rtrim no resultado quando o consumidor é exigente
Valores envoltos num banco de dados newlines caem dentro de uma coluna TEXT e o próximo SELECT devolve um token quebrado guarde a forma em uma linha; quebre só no destino
Variáveis de ambiente com blobs grandes o crescimento de 33 por cento mais o limite por argumento do sistema operacional mata o processo filho no spawn com um erro obscuro valores pequenos no ambiente, valores grandes num arquivo ou num banco de dados
Pressupor que Base64 é proteção o formato não esconde nada, e o registro público documenta incidentes reais em que um usuário colou uma troca IMAP e revelou uma senha sem querer trate a saída como confidencial desde o momento em que ela é produzida, e mantenha ela fora de logs
Planejar sem a conta de tamanho uma imagem de 500 KB vira 670 KB de texto, e o limite de armazenamento ou payload que você não conferiu morde reserve 4/3 do tamanho original antes de se comprometer

Uma história contada pelo codificador

O codificador Base64 do Perl tem uma carreira que vale um minuto, e ela começa na primeira toolkit web:

  • Nascido no libwww perl. O codificador começou a vida como LWP::Base64, escrito por Martijn Koster e Joerg Reichelt, que o Gisle Aas absorveu no libwww perl como MIME::Base64; ele se formou na própria distribuição do CPAN em abril de 1997, versão 2.00, com uma entrada no changelog que diz simplesmente que é baseado no libwww perl 5.08.
  • A era da velocidade. A versão 2.07 em 1998 embarcou uma implementação C mais rápida e mais inteligente do decodificador, mais ou menos 25 por cento mais veloz nas caixas Linux modernas da época, e o ajuste continuou por uma década.
  • A era do Unicode. O Perl 5.8 em 2002 trouxe caracteres com códigos acima de 255 para strings comuns, e o módulo respondeu em etapas: o 2.12 em 2001 rebaixava strings UTF-8 antes de codificar, e o croak moderno de Wide character in subroutine entry é o jeito do codificador de manter aquela promessa. A sincronização 2.13 com o core naquele mesmo ano trouxe o suporte EBCDIC junto, um lembrete de que o Base64 no Perl ainda roda em mainframes.
  • A era da linha de comando. Releases do 2.14 em 2003 ao 3.05 em 2004 incluíam um comando encode-base64 de verdade, junto com os gêmeos dele de decode e quoted-printable; o 3.06 em 2005 moveu os scripts para a distribuição separada MIME Base64 Scripts.
  • A chegada do URL-safe. A RFC 4648 padronizou o alfabeto URL-safe em 2006, um módulo standalone MIME::Base64::URLSafe apareceu no mesmo ano, e o módulo core alcançou em 3.11 em 2010 com o encode_base64url em uma única chamada.
  • A linha moderna. A versão 3.16 em 2020 refez o empacotamento e subiu o piso para o Perl 5.6; os Perls core atuais embarcam a série 3.16, e o módulo é mantido dentro da distribuição core, que é praticamente o lar mais seguro que um módulo core pode ter.

Fatos curiosos, especificamente do Perl

As curiosidades que fazem desta história uma boa história:

  • O exemplo do POD é uma frase mágica. Desde 1997, a documentação própria do módulo codifica Aladdin:open sesame, então a string QWxhZGRpbjpvcGVuIHNlc2FtZQ== é o cartão de visitas do módulo há quase trinta anos.
  • O fim de linha padrão é o que você provavelmente não esperava. É um \n simples, não o CRLF que o MIME fala. A própria convenção da RFC precisa do segundo argumento, e o módulo embarca com o padrão do programador, não o do protocolo.
  • A string vazia tem uma regra especial. Codifique nada e você recebe nada de volta, sem newline anexado: a única exceção documentada à regra do eol no final, e a razão pela qual um arquivo vazio vai e volta certinho.
  • O primo IMAP tem uma vírgula. A variante de nome de mailbox da RFC 3501 troca o / por uma vírgula no alfabeto, então uma string Base64 de um servidor IMAP pode conter uma letra que o decodificador padrão trata como ruído.
  • A linhagem de 1991 é real. A implementação C descende do metamail, o programa de e-mail da Bellcore de 1991, três anos antes de o Perl 5 nascer, então cada chamada de encode_base64 é em parte código dos anos 90.
  • O gêmeo puro em Perl tem a própria história. Quando a versão 3.00 em 2004 removeu as implementações puras em Perl do módulo core, o changelog as chamou de gordura que esconde problemas de verdade nas implementações XS e as re-lançou como MIME::Base64::Perl, onde elas ainda moram.

Então da próxima vez que bytes crus precisarem viajar por um mundo só de texto, você sabe a história inteira. Uma chamada de função faz o trabalho, o newline escondido é uma decisão que você toma com o segundo argumento, o croak de caractere largo é o jeito do codificador de manter o seu Unicode honesto, o dialeto URL-safe é uma chamada desde 2010, arquivos fazem stream em chunks de 57 bytes, e a conta de 33 por cento é o preço da entrada. E se um dia você precisar fazer a viagem na direção oposta, pegar uma string de letras e trazer os bytes originais de volta, o artigo relacionado sobre decodificação Base64 em Perl, linkado abaixo, cobre esse ritual na mesma profundidade.

Última atualização: 2026-09-08

Artigo relacionado: Decodificação Base64 em Perl: um guia completo