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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: drew at elysium dot demon dot co dot uk
New email:
PHP Version: OS:

 

 [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

Pull Requests

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-2025 The PHP Group
All rights reserved.
Last updated: Sun May 11 12:01:27 2025 UTC