Q: Base64 in Java and PHP The following Java code:
String ss = Base64.encodeBase64URLSafeString(xmlRequest.getBytes());
System.out.println(ss);

Produces:
PHJlcXVlc3Q-PG1lcmNoYW50X2lkPjQ2PC9tZXJjaGFudF9pZD48b3JkZXJfaWQ-MzM8L29yZGVyX2lkPjxhbW91bnQ-MzwvYW1vdW50PjxkZXNjcmlwdGlvbj5oZWhlPC9kZXNjcmlwdGlvbj48L3JlcXVlc3Q-

While this PHP code:
$xml='<request><merchant_id>46</merchant_id><order_id>33</order_id><amount>3</amount><description>hehe</description></request>';
$xml_encoded = base64_encode($xml);

Produces:
    PHJlcXVlc3Q+PG1lcmNoYW50X2lkPjQ2PC9tZXJjaGFudF9pZD48b3JkZXJfaWQ+MzM8L29yZGVyX2lkPjxhbW91bnQ+MzwvYW1vdW50PjxkZXNjcmlwdGlvbj5oZWhlPC9kZXNjcmlwdGlvbj48L3JlcXVlc3Q+
One of them has - characters, while the other one has +. Where does the difference come from?

A: See this article for some of the variants in use. Looks like - is used when the representation needs to be safe for including in an URL e.g. as a query argument. See also the Base64 source code:
/**
 * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet"
 * equivalents as specified in Table 1 of RFC 2045.
 *
 * Thanks to "commons" project in ws.apache.org for this code.
 * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
 */
private static final byte[] STANDARD_ENCODE_TABLE = {
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};

/**
 * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and /
 * changed to - and _ to make the encoded Base64 results more URL-SAFE.
 * This table is only used when the Base64's mode is set to URL-SAFE.
 */
private static final byte[] URL_SAFE_ENCODE_TABLE = {
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
};


A: Base 64 is the characters a-zA-Z0-9 as well as + and / for the last two.
In order to make the encoding URL safe, we cannot use / so the last two characters are replaced by the URL safe variants _ and -.
If you use:
final Base64.Encoder encoder = Base64.getEncoder();
encoder.encodeToString(...)

You will get the same output as the PHP example.
P.S. this is the new java.util.Base64 class built into the JDK - no need to use the arcane Common library.

A: This is because the "URL-Safe Base64 Variant" used by Base64.encodeBase64URLSafeString() replaces + and / with - and _:

Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The url-safe variation emits - and _ instead of + and / characters. Note: no padding is added.

You can simply translate the two formats by changing + and / into - and _.
To get an output identical to PHP's, just use Base64.encodeBase64String().
