如何检查一个字符串是否是base64编码的?

How to check whether a string is base64 encoded or not?

我想检查 HTML img src 在我的 java spring 后端是否是 base64 编码格式。如果它是 Base64 编码的那么我将只解码图像并保存到我的服务器如果不是我将首先根据图像 URL 路径下载然后保存到我的服务器。我已经构建了下载图像和解码图像功能。但是无法解析base64校验。我尝试使用 try catch 检查语句,但如果不是 base64,则不需要捕获错误。 P.S 我正在使用 java.util.Base64

public boolean isBase64(String path) {
   try {
        Base64.getDecoder().decode(path);

    } catch(IllegalArgumentException e) {   
    }
}

从理论上讲,您无法确定某个字符串是否经过 base64 解码,因为偶然情况下任何常规字符串都可能是 base64 可解码的。

然而实际上,对于较长的数据,它是 base64 可解码但不是 base64 编码数据的可能性很小。

总的来说我没有发现你的方法有问题,你的方法只需要一些小的改进:

public boolean isBase64(String path) {
   try {
        Base64.getDecoder().decode(path);
        return true;
    } catch(IllegalArgumentException e) {   
        return false;
    }
}

在我看来,这种方法效率很低,因为如果数据是 base64 可解码的,我假设您需要 base64 解码的数据。因此,在这种情况下,您将执行两次 base64 解码(一次用于检查 isBase64,一次用于实际编码)。因此我会使用这样的东西:

public byte[] tryDecodeBase64(String path) {
   try {
        return Base64.getDecoder().decode(path);
    } catch(IllegalArgumentException e) {   
        return null;
    }
}

如果您通过 <img src="..." /> 属性收到准确的值,那么它应该有 Data URL format

简单的正则表达式可以确定 URL 是数据还是常规。在 java 中它看起来像

    private static final Pattern DATA_URL_PATTERN = Pattern.compile("^data:image/(.+?);base64,\s*", Pattern.CASE_INSENSITIVE);

    static void handleImgSrc(String path) {
        if (path.startsWith("data:")) {
            final Matcher m = DATA_URL_PATTERN.matcher(path);
            if (m.find()) {
                String imageType = m.group(1);
                String base64 = path.substring(m.end());
                // decodeImage(imageType, base64);
            } else {
                // some logging
            }
        } else {
            // downloadImage(path);
        }
    }

我仍然不确定您是在查看 URL 还是想检查数据。
对于后者,你可以这样做...

/*
 * Some typical Image-File Signatures (starting @ byte 0)
 */
private static final byte[] JPG_1 = new byte[] {-1, -40, -1, -37};
private static final byte[] JPG_2 = new byte[] {-1, -40, -1, -18};
private static final byte[] PNG   = new byte[] {-119, 80, 78, 71, 13, 10, 26, 10};

public static boolean isMime(final InputStream ist) {
    /*
     * The number of bytes of Mime-encoded Data you want to read.
     * (4 * 19 = 76, which is MIMELINEMAX from Base64$Encoder)
     */
    final int    mimeBlockLength  =  4;  // <- MUST be 4!
    final int    mimeBlockCount   = 19;  // <- your choice
    final int    mimeBufferLength = mimeBlockCount * mimeBlockLength;

    final byte[] bar              = new byte[mimeBufferLength];

    try (final BufferedInputStream bis = new BufferedInputStream(ist, mimeBufferLength))
    {
        /*
         * We expect at least one complete Mime-encoded buffer...
         */
        if (bis.read(bar) != mimeBufferLength) {
            return false;
        }
        /*
         * Use a Java 9 feature to compare Signatures...
         */
        if (Arrays.equals(bar, 0, JPG_1.length, JPG_1, 0, JPG_1.length)
        ||  Arrays.equals(bar, 0, JPG_2.length, JPG_2, 0, JPG_2.length)
        ||  Arrays.equals(bar, 0, PNG  .length, PNG  , 0, PNG  .length)) {
            return true;
        } else {
            return false;
        }
    } catch (final IOException e) {
        return false;
    }
}

test Base64.getDecoder().decode(input) return true always...:-( 试试这个(对我有用):

private boolean testStringIsBase64(String input) {
  boolean result = false;
  String test;
  try {
    test = convertStringFromBase64(input);
    if (input.equals(convertStringToBase64(test))) {
      result = true;
    }
  }
  catch (Exception ex) {
    result = false;
  }
  return result;
}

private String convertStringToBase64(String input) {
  return Base64.getEncoder().encodeToString(input.getBytes());
}

private String convertStringFromBase64(String input) {
  return new String(Base64.getDecoder().decode(input));
}

每当您尝试编码并返回解码并且字符串相同时,输入都是 Base64

R.