php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #967 Base 64
Submitted: 1998-12-03 10:55 UTC Modified: 1998-12-28 05:06 UTC
From: drew at elysium dot demon dot co dot uk Assigned:
Status: Closed Package: Other
PHP Version: 3.0.5 OS: Linux 2.0.xx
Private report: No CVE-ID: None
 [1998-12-03 10:55 UTC] drew at elysium dot demon dot co dot uk
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;
 }

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [1998-12-28 05:06 UTC] sas
Thanks for your contribution. Unfortunately, it would break backwards compatibility.

If you need this functionality, use chunk_split() to split up base64_encode'd strings. 
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon May 06 21:01:34 2024 UTC