php5でのbase64_decodeバグ修正方法

たまには技術的なことを書きます。
現在phpの最新バージョン8.xですが、いまだにphp5を使い続けているシステムも多く存在します。
phpを常に最新バージョンにする運用を行うというのが理想ですが、バージョンアップに対応できていないphpプログラムの変更やバージョンアップによるバグの混入など、そのような運用は現実的ではありません。
しかしphp5はすでにサポートも打ち切られているため、システム上問題があった場合は最新のソースコードを参考に自分でソースコードを修正しphpを再構築する必要があります。
そんなこんなで担当しているシステムにおいてbase64_decodeの不具合が発生しました。現象としてはbase64_encodeしたデータがデコード出来ないというものでした。

test.php

<php 
{ 
$str = "YTo0Nzp7czo4OiJydF9kYXRlcyI7YToyOntpOjE7czoxMDoiMjAyNC0wMS0yMSI7aToyO3M6MTA6IjIwMjQtMDEtMjEiO31zOjg6InJ0X3N0b3BzIjthOjI6e2k6MTtzOjA6IiI7aToyO3M6NToiMjE6MzAiO31zOjk6InJ0X3N0YXJ0cyI7YToyOntpOjE7czo1OiIxNzozMCI7aToyO3M6MDoiIjt9czo5OiJydF9wbGFjZXMiO2E6Mjp7aToxO3M6MjQ6IiDmiJDnlLDnqbrmuK9UMuOAgChNSDcwKSI7aToyO3M6MjE6IkhPVEVMIEdST09WRSBTSElOSlVLVSI7fXM6NjoicnRfa2JzIjthOjI6e2k6MTtzOjA6IiI7aToyO3M6MDoiIjt9czo2OiJydF9yZHMiO2E6Mjp7aToxO3M6MDoiIjtpOjI7czowOiIiO31zOjk6InJ0X2thaXNvcyI7YToyOntpOjE7TjtpOjI7Tjt9czo4OiJydF93YXJucyI7YToyOntpOjE7TjtpOjI7Tjt9czo5OiJydF9tZXRlcnMiO2E6Mjp7aToxO3M6MDoiIjtpOjI7czowOiIiO31zOjU6InJtaW5zIjthOjI6e2k6MTtzOjA6IiI7aToyO3M6MDoiIjt9czo4OiJydF9yZXN0cyI7YToyOntpOjE7TjtpOjI7Tjt9czo5OiJydF9zbGVlcHMiO2E6Mjp7aToxO047aToyO047fXM6ODoicnRfY2VuZHMiO2E6Mjp7aToxO047aToyO047fXM6MTA6InJ0X2NzdGFydHMiO2E6Mjp7aToxO047aToyO047fXM6ODoicnRfZnVrdXMiO2E6Mjp7aToxO3M6MToiMCI7aToyO3M6MToiMCI7fXM6MTA6InJ0X2Z1a3VfZXMiO2E6Mjp7aToxO3M6MToiMCI7aToyO3M6MToiMCI7fXM6MTI6InJ0X3N0X3BsYWNlcyI7aToxO3M6MTI6InJ0X2ZyX3BsYWNlcyI7aToxO3M6MTI6InJ0X3RvX3BsYWNlcyI7TjtzOjEyOiJydF9ydF9wbGFjZXMiO2k6MjtzOjEyOiJydF9lZF9wbGFjZXMiO2k6MjtzOjEyOiJydF9yZXN0X21pbnMiO2E6Mjp7aToxO047aToyO047fXM6MTE6InJ0X3Jlc3RfZHRzIjthOjI6e2k6MTtOO2k6MjtOO31zOjc6ImxhdGxvbnMiO2E6Mjp7aToxO3M6MDoiIjtpOjI7czowOiIiO31zOjg6ImV4X3VfbWluIjtzOjExOiIoNngrMHgpeDEuMSI7czo4OiJleF91X21heCI7czoxMToiKDZ4KzB4KXgxLjEiO3M6ODoiZXhfcl9taW4iO3M6MTA6IigxeHgwKXgxLjEiO3M6ODoiZXhfcl9tYXgiO3M6MTI6IigxeHgwLjIpeDEuMSI7czo4OiJleF9qX3RhbiI7czoxOiIwIjtzOjEwOiJleF9raW5tdV9oIjtzOjE6IjYiO3M6ODoiZXhfa190YW4iO3M6MDoiIjtzOjc6ImV4X2tpbG8iO3M6MToiMCI7czo5OiJleF9jYWxfdXUiO3M6MToiMCI7czo5OiJleF9zcF90YW4iO3M6MDoiIjtzOjEwOiJleF91cl9yYXRlIjtzOjA6IiI7czoxMDoiZXhfeWFrYW5faCI7czoxOiIxIjtzOjk6ImV4X2NhbF91ciI7czoxOiIwIjtzOjEzOiJleF9wcmljZV9uYW1lIjtOO3M6MTA6ImV4X3NwX2t0YW4iO3M6MDoiIjtzOjE1OiJleF9nZF9hc2FfdGVhdGUiO047czoxNjoiZXhfZ2RfeW9ydV90ZWF0ZSI7TjtzOjE1OiJleF9nZF9kYWlfdGVhdGUiO047czoxNjoiZXhfZ2RfeWFrb190ZWF0ZSI7TjtzOjE2OiJleF9nZF9rb3R1X3RlYXRlIjtOO3M6MTY6ImV4X2dkX290aDFfdGVhdGUiO047czoxNjoiZXhfZ2Rfb3RoMl90ZWF0ZSI7TjtzOjE2OiJleF9nZF9vdGgzX3RlYXRlIjtOO30=',uk_sche=null,uk_stay='YTo2OntzOjg6InN0X2RhdGVzIjthOjE6e2k6MTtzOjEwOiIyMDI0LTAxLTIxIjt9czo4OiJzdF9uYW1lcyI7YToxOntpOjE7czoyMToiSE9URUwgR1JPT1ZFIFNISU5KVUtVIjt9czo4OiJzdF9hZHJzcyI7YToxOntpOjE7czozNjoi5p2x5Lqs6YO95paw5a6/5Yy65q2M6Iie5LyO55S6MS0yOS0xIjt9czo5OiJzdF9waG9uZXMiO2E6MTp7aToxO3M6MTI6IjAzLTYyMzMtODg4OCI7fXM6Njoic3Rfa2JzIjthOjE6e2k6MTtzOjI6IjEzIjt9czo3OiJpc19kdW1zIjthOjE6e2k6MTtzOjA6IiI7fX0="; 

print $str."\n";
 print "-------------\n"; 
$str = base64_decode($str); // decode出来ないため、strがNULLになってしまう。
print_r(unserialize($str)); 
} 
?>

php7だとデコード出来るため、phpのプログラムの不具合であることが分かりソースコード(base64.c)を以下のように修正しました。

~/ext/standard/base64.c

149 PHPAPI unsigned char *php_base64_decode_ex(const unsigned char *str, int length, int *ret_length, zend_bool strict) /* {{{ */
150 {
151     const unsigned char *current = str;
152     int ch, i = 0, j = 0, padding = 0;
153     /* this sucks for threaded environments */
154     unsigned char *result;
155
156     result = (unsigned char *)safe_emalloc(length, 1, 1);
157
158     /* run through the whole string, converting as we go */
159     while (length-- > 0) {
160         ch = *current++;
161         if (ch == base64_pad) {
162             padding++;
163             continue;
164         }
165
166         ch = base64_reverse_table[ch];
167         if (!strict) {
168             /* skip unknown characters and whitespace */
169             if (ch < 0) {
170                 continue;
171             }
172         } else {
173             /* skip whitespace */
174             if (ch == -1) {
175                 continue;
176             }
177             /* fail on bad characters or if any data follows padding */
178             if (ch == -2 || padding) {
179                 efree(result);
180                 return NULL;
181             }
182         }
183
184         switch(i % 4) {
185         case 0:
186             result[j] = ch << 2; 187 break; 188 case 1: 189 result[j++] |= ch >> 4;
190             result[j] = (ch & 0x0f) << 4; 191 break; 192 case 2: 193 result[j++] |= ch >>2;
194             result[j] = (ch & 0x03) << 6; 195 break; 196 case 3: 197 result[j++] |= ch; 198 break; 199 } 200 i++; 201 } 202 /* fail if the input is truncated (only one char in last group) */ 203 if (strict && i % 4 == 1) { 204 efree(result); 205 return NULL; 206 } 207 208 if (strict && padding && (padding > 2 || (i + padding) % 4 != 0)) {
209         efree(result);
210         return NULL;
211     }
212
213     if(ret_length) {
214         *ret_length = j;
215     }
216     result[j] = '\0';
217     return result;
218 }

修正後、phpをmake後、コマンドラインで
./sapi/cli/php ./test.php
を実行し、正しくデコード出来ることを確認後、サーバ上にてmake installを実行しました。
このような対応はyumなどパッケージインストールでは対応が難しく、C言語などの知識は必須となります。

そんなこんなでLAMP関連を使ったシステムでお困りの企業様はガイドミーにご相談ください!