|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
[1998-12-28 05:06 UTC] sas
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sun Oct 26 05:00:01 2025 UTC |
I have been base64 encoding some reasonably large files using the base64_encode function and the encoded string gets returned as one long string. I had a look at RFC2045 (as mentioned in the manual documenting either base64_encode or base64_decode) and it mentions that a line in the encoded string should be no longer than 76 chars and also that when decoding an encoded string then whitespace and newlines should be ignored. Anyway splitting a large base64 encoded string into 76 character lines is very slow if done in the following way :- $encode = base64_Encode($data); while (strLen($encode)) { $mail .= subStr($encode, 0, 76); $encode = subStr($encode, 76); } So I include a patch to make base64_encode & base64_decode a little more RFC2045 compliant, please let me know if there are any problems with doing this. Included in this patch is a fix for an extra byte problem in base64_decode (the j++ is done in the 'upper' case 3:, so its is not needed in the 'lower' case 3: - I think) --- base64.c.orig Thu Dec 3 14:45:13 1998 +++ base64.c Thu Dec 3 15:47:43 1998 @@ -45,19 +45,30 @@ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0' }; static char base64_pad = '='; +static char base64_newline = '\n'; unsigned char *_php3_base64_encode(const unsigned char *string, int length, int *ret_length) { const unsigned char *current = string; int i = 0; - unsigned char *result = (unsigned char *)emalloc(((length + 3 - length % 3) * 4 / 3 + 1) * sizeof(char)); + size_t emalloc_length = 0; + unsigned char *result; + + emalloc_length += ((length + 3 - length % 3) * 4 / 3 + 1) * sizeof(char); + emalloc_length += (((emalloc_length - 1) / 76) + 1) * sizeof(char); + result = (unsigned char *)emalloc(emalloc_length); while (length > 2) { /* keep going until we have less than 24 bits */ result[i++] = base64_table[current[0] >> 2]; result[i++] = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)]; result[i++] = base64_table[((current[1] & 0x0f) << 2) + (current[2] >> 6)]; result[i++] = base64_table[current[2] & 0x3f]; - current += 3; + /* if we are a multiple of 57 bytes away from the start of the + source string (which translates into 76 bytes away from the + start of the destination) then add a line feed */ + if (!((current - string) % 57)) + result[i++] = base64_newline; + length -= 3; /* we just handle 3 octets of data */ } @@ -75,10 +86,12 @@ result[i++] = base64_pad; } } - if(ret_length) { + result[i++] = base64_newline; + result[i] = '\0'; + + if (ret_length) { *ret_length = i; } - result[i] = '\0'; return result; } @@ -86,8 +99,12 @@ unsigned char *_php3_base64_decode(const unsigned char *string, int length, int *ret_length) { const unsigned char *current = string; int ch, i = 0, j = 0; + size_t emalloc_length = 0; + unsigned char *result; + + emalloc_length = (length / 4 * 3 + 1) * sizeof(char); + result = (unsigned char *)emalloc(emalloc_length); - unsigned char *result = (unsigned char *)emalloc((length / 4 * 3 + 1) * sizeof(char)); if (result == NULL) { return NULL; } @@ -95,6 +112,7 @@ /* run through the whole string, converting as we go */ while ((ch = *current++) != '\0') { if (ch == base64_pad) break; + if (ch == base64_newline || ch == ' ' || ch == '\t') continue; ch = (int)strchr(base64_table, ch); if (ch == 0) { efree(result); @@ -130,14 +148,13 @@ return NULL; case 2: j++; - case 3: - result[j++] = 0; } } - if(ret_length) { + result[j] = '\0'; + + if (ret_length) { *ret_length = j; } - result[j] = '\0'; return result; }