将以C语言(\0结尾)表示的字符串转换为PHP字符串。

4

PHP是我偶尔使用的一种语言,但通常在重新开始使用时需要清除灰尘。本周我正在将一些C代码移植到PHP上,这需要大量使用AES加密和SHA256哈希算法 - 到目前为止都正常工作。但是,解密后的字符串以“C”形式输出 - 即以零字节结尾,后跟“垃圾”填充字节。

我目前使用以下方法将这些C风格的字符串转换为PHP格式:

$iv = strpos( $hashsalt8, "\0");
if ($iv)
   $hashsalt8 = substr( $hashsalt8, 0, $iv );

似乎有点冗长,应该有一个一行函数调用的替代方法,但我找不到它?

注意:尽管在这种情况下,“哈希盐”名称暗示我可能知道原始字符串的长度,但在一般情况下未知。当长度是先验已知的时,可以使用substr()获得一个一行解决方案。

3个回答

6
使用 strstr 函数:
$hashsalt8 = strstr($hashsalt8, "\0", TRUE);

对于版本低于5.3.0的情况(第三个参数不可用),使用 strrevsubstrstrrchr 函数可以得到一个更加丑陋的解决方案:

$hashsalt8 = strrev(substr(strrchr(strrev($hashsalt8), "\0"), 1));

3
请注意,第三个参数仅适用于 PHP 5.3 及以上版本。 - BoltClock
啊,这就解释了:我在 PHP 5.1.6 上运行时出现了“参数数量错误”的错误。如果这是我的服务器,我可能会覆盖提供的 PHP,但它不是我的,所以我不会尝试。 - winwaed
这似乎是针对使用较新版本PHP的人的答案。如果没有其他适用于PHP 5.1.6的内容,我将在明天将其标记为答案。 - winwaed
1
@winwaed:为版本<5.3.0添加了一个不太优雅的解决方案。 - You
1
是的,不够优雅。我想我还是会坚持我现在的做法,承认你原来的strstr()方法对于PHP的后续版本来说是最好的。我会将其标记为答案。 - winwaed

1

应该永远不需要超过32个字节的填充,是吗?(来自您在此处的评论)

您可以尝试像这样做:

preg_replace('/\x00.{0,32}$/', "", $hashsalt8);

请注意使用单引号而不是双引号,如果使用双引号,则\x00会破坏preg :)

似乎有32个字节:第一次实例中目前有15个字节的垃圾数据。这是一个有趣的方法,但简单性可能是一个主观的事情(我倾向于不喜欢在处理简单问题时使用正则表达式)。 - winwaed
可以使用双引号,只需转义反斜杠即可获得\\x00,PHP不会将其解释为空字节,而是\x00 - BoltClock

1

strtok函数将在一次遍历中完成而不是两次遍历:

$hashsalt8 = strtok($hashsalt8, "\0");

然而,从PHP 4.1.0开始,如果输入字符串以零字节开头,strtok将不返回空字符串。您可以执行以下操作来处理该情况:

if ($hashsalt8[0] == "\0") {
  $hashsalt8 = '';
}
else {
  $hashsalt8 = strtok($hashsalt8, "\0");
}

注意,以零字节开头的输入字符串也会暴露出您当前代码中的一个错误。在这种情况下,strpos将返回0并且if($iv)会失败。

您应该使用!==运算符来区分0false:

$iv = strpos($hashsalt8, "\0");
if ($iv !== false) {
   $hashsalt8 = substr($hashsalt8, 0, $iv);
}

谢谢!是的,那会很“简单”。感谢您提到“!==”运算符的注意事项。我不认为这种情况会发生在我的特定代码中,但对于一般情况(甚至是安全编程),这显然是正确的做法。 - winwaed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接