PHP字符串转换为十六进制和十六进制转换为字符串

71

在 PHP 中转换这两种类型时,我遇到了问题。以下是我在 Google 上搜索到的代码:

function strToHex($string){
    $hex='';
    for ($i=0; $i < strlen($string); $i++){
        $hex .= dechex(ord($string[$i]));
    }
    return $hex;
}


function hexToStr($hex){
    $string='';
    for ($i=0; $i < strlen($hex)-1; $i+=2){
        $string .= chr(hexdec($hex[$i].$hex[$i+1]));
    }
    return $string;
}

我检查了一下,当我使用XOR加密时发现了这个问题。

我有一个字符串"this is the test",用一个密钥进行XOR运算后,得到的结果是字符串↕↑↔§P↔§P ♫§T↕§↕。然后,我尝试通过函数strToHex()将其转换为十六进制,得到了这些12181d15501d15500e15541215712。接着,我用函数hexToStr()进行测试,得到的结果是↕↑↔§P↔§P♫§T↕§q。那么,我应该怎么解决这个问题?为什么在转换这两种样式的值时会出错?


10
你知道PHP里有hex2bin()bin2hex()吗? - जलजनक
strToHex 返回一个十六进制的字符串 - 因此,如果您直接使用 ^ 运算符对其进行异或运算,那么结果可能不好。也许您可以给 strToHex 另一个参数,即您想要进行异或运算的数字,并在该函数内部直接进行异或运算:$hex .= dechex(ord($string[$i]) ^ $MYKEYBYTE); - Déjà vu
我认为问题出在hexToStr()函数上。因为当它转换为字符串时,会传递空格或一些特殊字符,从而导致问题。 - JoeNguyen
我尝试了hex2bin()和bin2hex()函数。它们非常好用并且解决了问题,但在实际情况下却行不通。只有当我在使用XOR加密明文后调用bin2hex()函数时才能得到正确的结果。然而,在实际情况中,我们通常会在XOR之后使用strToHex()函数,所以当我们通过XOR解密加密文本以获取明文时,调用hexToStr()函数将得到错误的结果。 - JoeNguyen
9个回答

139

对于那些来到这里只是寻找二进制字符串的十六进制表示的人。

bin2hex("that's all you need");
# 74686174277320616c6c20796f75206e656564

hex2bin('74686174277320616c6c20796f75206e656564');
# that's all you need

文档: bin2hex, hex2bin.


2的补码怎么样? - Moeez
我创建了一个包含此功能的gist。这是一个简单的PHP十六进制转储函数:https://gist.github.com/hopeseekr/9964a9f12428dd220c3dd29a9943ce65 - Theodore R. Smith

56

对于任何 ord($char) < 16 的字符,您会得到一个只有 1 位的十六进制数。您忘记添加 0 填充。

这样应该解决问题:

<?php
function strToHex($string){
    $hex = '';
    for ($i=0; $i<strlen($string); $i++){
        $ord = ord($string[$i]);
        $hexCode = dechex($ord);
        $hex .= substr('0'.$hexCode, -2);
    }
    return strToUpper($hex);
}
function hexToStr($hex){
    $string='';
    for ($i=0; $i < strlen($hex)-1; $i+=2){
        $string .= chr(hexdec($hex[$i].$hex[$i+1]));
    }
    return $string;
}


// Tests
header('Content-Type: text/plain');
function test($expected, $actual, $success) {
    if($expected !== $actual) {
        echo "Expected: '$expected'\n";
        echo "Actual:   '$actual'\n";
        echo "\n";
        $success = false;
    }
    return $success;
}

$success = true;
$success = test('00', strToHex(hexToStr('00')), $success);
$success = test('FF', strToHex(hexToStr('FF')), $success);
$success = test('000102FF', strToHex(hexToStr('000102FF')), $success);
$success = test('↕↑↔§P↔§P ♫§T↕§↕', hexToStr(strToHex('↕↑↔§P↔§P ♫§T↕§↕')), $success);

echo $success ? "Success" : "\nFailed";

2
在strToHex函数中,作为dechex()和substr -2的替代方案,可以使用$hex .= sprintf('%02.x', $ord); - tropicalm
如果是16位的情况,我该怎么办? - Moeez

37

PHP:

字符串转十六进制:

implode(unpack("H*", $string));

十六进制转字符串:

pack("H*", $hex);

1
你可以通过使用 list 来避免调用 implode,例如:list(, $hex) = unpack('H*', $string); - Geoffrey
64的十六进制值是40。但它返回给我其他东西。 - Moeez

13

这是我使用的:

function strhex($string) {
  $hexstr = unpack('H*', $string);
  return array_shift($hexstr);
}

使用2的补码进行转换? - Moeez

1
使用@bill-shirley的答案并进行了一点补充。
function str_to_hex($string) {
$hexstr = unpack('H*', $string);
return array_shift($hexstr);
}
function hex_to_str($string) {
return hex2bin("$string");
}

使用方法:

  $str = "Go placidly amidst the noise";
  $hexstr = str_to_hex($str);// 476f20706c616369646c7920616d6964737420746865206e6f697365
  $strstr = hex_to_str($str);// Go placidly amidst the noise

为什么不先转换带重音的字符呢? - PeterT
有任何特定推荐的方法吗?mb_convert_encoding?虽然这超出了最初的范围,但十六进制信息将在MSSQL中转换回字符串,而该数据库没有解码功能。 - ner0

1
function hexToStr($hex){
    // Remove spaces if the hex string has spaces
    $hex = str_replace(' ', '', $hex);
    return hex2bin($hex);
}
// Test it 
$hex    = "53 44 43 30 30 32 30 30 30 31 37 33";
echo hexToStr($hex); // SDC002000173

/**
 * Test Hex To string with PHP UNIT
 * @param  string $value
 * @return 
 */
public function testHexToString()
{
    $string = 'SDC002000173';
    $hex    = "53 44 43 30 30 32 30 30 30 31 37 33";
    $result = hexToStr($hex);

    $this->assertEquals($result,$string);
}

1
以下是将十六进制转换为字符串的方法:
    $s = '\x64\x65';
    $t = array_map(function($item){
        return pack("H*", $item);
    }, explode('/x', $s));
    $result = implode('', $t);

0

我只有一半的答案,但我希望它有用,因为它增加了Unicode(UTF-8)支持。

    /**
     * hexadecimal to unicode character
     * @param  string  $hex
     * @return string
     */
    function hex2uni($hex) { 
      $dec = hexdec($hex);
        if($dec < 128) {
            return chr($dec);
        }
        if($dec < 2048) {
            $utf = chr(192 + (($dec - ($dec % 64)) / 64));
        } else {
            $utf = chr(224 + (($dec - ($dec % 4096)) / 4096));
            $utf .= chr(128 + ((($dec % 4096) - ($dec % 64)) / 64));
        }
        return $utf . chr(128 + ($dec % 64));
    }

转换为字符串

    var_dump(hex2uni('e641'));

基于:http://www.php.net/manual/zh/function.chr.php#Hcom55978

0
您可以尝试以下代码将图像转换为十六进制字符串。
<?php
$image = 'sample.bmp';
$file = fopen($image, 'r') or die("Could not open $image");
while ($file && !feof($file)){
$chunk = fread($file, 1000000); # You can affect performance altering
this number. YMMV.
# This loop will be dog-slow, almost for sure...
# You could snag two or three bytes and shift/add them,
# but at 4 bytes, you violate the 7fffffff limit of dechex...
# You could maybe write a better dechex that would accept multiple bytes
# and use substr... Maybe.
for ($byte = 0; $byte < strlen($chunk); $byte++)){
echo dechex(ord($chunk[$byte]));
}
}
?>

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