如何在 PHP 中获取字符串的十六进制转储?
Posted
技术标签:
【中文标题】如何在 PHP 中获取字符串的十六进制转储?【英文标题】:How can I get a hex dump of a string in PHP? 【发布时间】:2010-11-06 15:40:25 【问题描述】:我正在研究 php5 中的编码。有没有办法得到一个字符串的原始十六进制转储?即字符串中每个字节(不是字符)的十六进制表示?
【问题讨论】:
一些不错的小在线工具 srsbiz.pl/utils/hexit.php 是 php 源:gist.github.com/4639219 - 可能有用,感谢@dev-null-dweller github.com/clue/php-hexdump 【参考方案1】:echo bin2hex($string);
或:
for ($i = 0; $i < strlen($string); $i++)
echo str_pad(dechex(ord($string[$i])), 2, '0', STR_PAD_LEFT);
$string
是包含输入的变量。
【讨论】:
或者更实用的方法:print_r(array_map('dechex', array_map('ord', str_split($string))));【参考方案2】:为了调试二进制协议,我需要一个更传统的 HEX 转储,所以我写了这个函数:
function hex_dump($data, $newline="\n")
static $from = '';
static $to = '';
static $width = 16; # number of bytes per line
static $pad = '.'; # padding for non-visible characters
if ($from==='')
for ($i=0; $i<=0xFF; $i++)
$from .= chr($i);
$to .= ($i >= 0x20 && $i <= 0x7E) ? chr($i) : $pad;
$hex = str_split(bin2hex($data), $width*2);
$chars = str_split(strtr($data, $from, $to), $width);
$offset = 0;
foreach ($hex as $i => $line)
echo sprintf('%6X',$offset).' : '.implode(' ', str_split($line,2)) . ' [' . $chars[$i] . ']' . $newline;
$offset += $width;
这会产生一个更传统的 HEX 转储,如下所示:
hex_dump($data);
=>
0 : 05 07 00 00 00 64 65 66 61 75 6c 74 40 00 00 00 [.....default@...]
10 : 31 42 38 43 39 44 30 34 46 34 33 36 31 33 38 33 [1B8C9D04F4361383]
20 : 46 34 36 32 32 46 33 39 32 46 44 38 43 33 42 30 [F4622F392FD8C3B0]
30 : 45 34 34 43 36 34 30 33 36 33 35 37 45 35 33 39 [E44C64036357E539]
40 : 43 43 38 44 35 31 34 42 44 36 39 39 46 30 31 34 [CC8D514BD699F014]
请注意,不可见字符将替换为句点 - 您可以更改每行的字节数 ($width) 和填充字符 ($pad) 以满足您的需要。我包含了一个 $newline 参数,因此如果您需要在浏览器中显示输出,可以传递 "<br/>"
。
【讨论】:
+1 非常好。太优秀了。我已经在某件事上工作了四个小时以上,这让我大受鼓舞。无论如何,我发现回显 pre 标记可以使其在浏览器中更好地显示。或使用 br 换行符。我是新手,想知道如何解密不可见的字符。 TNX。 爱它!需要一些改进,但作为调试工具的基础 - 它是完美的! @frostymarvelous 用于浏览器中的纯文本诊断输出,试试header('Content-type: text/plain');
- 派上用场:-)
这本质上就像在做od -tx1z
请为 $data 提供一个值。【参考方案3】:
几年过去了,但如果其他人也在搜索这个,我冒昧地修改了 mindplay.dk 的代码,使其接受各种选项并模拟 BSD 命令 hexdump -C 文件的输出:
/**
* Dumps a string into a traditional hex dump for programmers,
* in a format similar to the output of the BSD command hexdump -C file.
* The default result is a string.
* Supported options:
* <pre>
* line_sep - line seperator char, default = "\n"
* bytes_per_line - default = 16
* pad_char - character to replace non-readble characters with, default = '.'
* </pre>
*
* @param string $string
* @param array $options
* @param string|array
*/
function hex_dump($string, array $options = null)
if (!is_scalar($string))
throw new InvalidArgumentException('$string argument must be a string');
if (!is_array($options))
$options = array();
$line_sep = isset($options['line_sep']) ? $options['line_sep'] : "\n";
$bytes_per_line = @$options['bytes_per_line'] ? $options['bytes_per_line'] : 16;
$pad_char = isset($options['pad_char']) ? $options['pad_char'] : '.'; # padding for non-readable characters
$text_lines = str_split($string, $bytes_per_line);
$hex_lines = str_split(bin2hex($string), $bytes_per_line * 2);
$offset = 0;
$output = array();
$bytes_per_line_div_2 = (int)($bytes_per_line / 2);
foreach ($hex_lines as $i => $hex_line)
$text_line = $text_lines[$i];
$output []=
sprintf('%08X',$offset) . ' ' .
str_pad(
strlen($text_line) > $bytes_per_line_div_2
?
implode(' ', str_split(substr($hex_line,0,$bytes_per_line),2)) . ' ' .
implode(' ', str_split(substr($hex_line,$bytes_per_line),2))
:
implode(' ', str_split($hex_line,2))
, $bytes_per_line * 3) .
' |' . preg_replace('/[^\x20-\x7E]/', $pad_char, $text_line) . '|';
$offset += $bytes_per_line;
$output []= sprintf('%08X', strlen($string));
return @$options['want_array'] ? $output : join($line_sep, $output) . $line_sep;
这是一个小文件的十六进制转储:
00000000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 |.PNG........IHDR|
00000010 00 00 00 10 00 00 00 10 02 03 00 00 00 62 9d 17 |.............b..|
00000020 f2 00 00 00 09 50 4c 54 45 04 04 04 99 99 cc d7 |.....PLTE.......|
00000030 d7 d7 2a 66 f6 6b 00 00 00 38 49 44 41 54 78 9c |..*f.k...8IDATx.|
00000040 63 08 05 02 06 24 22 0b 44 24 01 89 ac a4 69 4b |c....$".D$....iK|
00000050 19 1a 16 68 70 31 74 29 75 2c 42 22 1a 16 75 00 |...hp1t)u,B"..u.|
00000060 c5 22 33 96 32 74 86 46 4c 65 58 19 1a 35 15 61 |."3.2t.FLeX..5.a|
00000070 00 00 df be 19 a6 2e 62 80 87 00 00 00 00 49 45 |.......b......IE|
00000080 4e 44 ae 42 60 82 |ND.B`.|
00000086
这是 phpunit 测试:
<?php
if (isset($argv))
print "Running outside of phpunit. Consider using phpunit.\n";
class PHPUnit_Framework_TestCase
class Test extends PHPUnit_Framework_TestCase
const FUNCTION_NAME = 'hex_dump';
const DATA_BASE64 = '
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAACVBMVEUEBASZmczX19cqZvZrAAAA
OElEQVR4nGMIBQIGJCILRCQBiaykaUsZGhZocDF0KXUsQiIaFnUAxSIzljJ0hkZMZVgZGjUVYQAA
374Zpi5igIcAAAAASUVORK5CYII=';
private $expect = array(
'00000000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 |.PNG........IHDR|',
'00000010 00 00 00 10 00 00 00 10 02 03 00 00 00 62 9d 17 |.............b..|',
'00000020 f2 00 00 00 09 50 4c 54 45 04 04 04 99 99 cc d7 |.....PLTE.......|',
'00000030 d7 d7 2a 66 f6 6b 00 00 00 38 49 44 41 54 78 9c |..*f.k...8IDATx.|',
'00000040 63 08 05 02 06 24 22 0b 44 24 01 89 ac a4 69 4b |c....$".D$....iK|',
'00000050 19 1a 16 68 70 31 74 29 75 2c 42 22 1a 16 75 00 |...hp1t)u,B"..u.|',
'00000060 c5 22 33 96 32 74 86 46 4c 65 58 19 1a 35 15 61 |."3.2t.FLeX..5.a|',
'00000070 00 00 df be 19 a6 2e 62 80 87 00 00 00 00 49 45 |.......b......IE|',
'00000080 4e 44 ae 42 60 82 |ND.B`.|',
'00000086',
);
public function testRequire()
$file = __DIR__ . '/' . static::FUNCTION_NAME . '.php';
$this->assertFileExists($file);
include($file);
$this->assertTrue(function_exists(static::FUNCTION_NAME));
public function testString()
$func = static::FUNCTION_NAME;
$data = base64_decode(static::DATA_BASE64);
if (!is_string($data))
throw new Exception('Unable to decode base64 encoded test data');
$dump = $func($data);
//var_export($dump);
$this->assertTrue(is_string($dump));
$this->assertEquals($dump, join("\n", $this->expect) . "\n");
if (isset($argv))
$func = Test::FUNCTION_NAME;
require_once($func . '.php');
if (count($argv) < 2)
print "Pass arguments file, from, length.\n";
else
$file = $argv[1];
if (!file_exists($file))
die("File not found: $file\n");
$from = isset($argv[2]) && preg_match('/^\d1,9$/', $argv[2]) ? intval($argv[2]) : null;
$len = isset($argv[3]) && preg_match('/^\d1,9$/', $argv[3]) ? intval($argv[3]) : filesize($file);
$h = fopen($file, 'r');
if ($from)
fseek($h, $from);
$data = fread($h, $len);
fclose($h);
$dump = hex_dump($data);
print $dump;
//$dump = hex_dump($data, array('want_array' => true));
//print_r($dump);
【讨论】:
最后一行00000086没用。 告诉 BSD 命令 hexdump 的作者。最后一行表示文件大小。【参考方案4】:在调试二进制协议时,我也需要一个 hexdump()。我决定将我的解决方案发布为 PEAR 包,因为它绝对有用。也可以在github上浏览代码。
梨:http://www.metashock.de/pear
GitHub:http://www.github.com/metashock/Hexdump
除了 mindplays 解决方案之外,它还支持正确渲染最后一行和其他参数。该软件包还包含一个名为 phphd 的 php 可执行文件,用于 cmdline 上的 hexdumps。这可能对 Windows 系统有帮助:)
@mindplay.dk:感谢 strtr() 的想法。它似乎比我以前的尝试要快一些。将其集成到我的版本中。 (使用减少的翻译缓冲区)..
【讨论】:
【参考方案5】:“功能”版本:
$s = "\x04\x00\xa0\x00";
echo implode(' ', array_map(function($char)
# return sprintf('%02s', $char);
return str_pad($char, 2, '0', STR_PAD_LEFT);
, array_map('dechex', unpack('C*', $s))));
借用 Ionuț G. Stan 的 comment,最后一行可能如下:
, array_map('dechex', array_map('ord', str_split($s)))));
【讨论】:
【参考方案6】: echo implode(array_map(
fn ($a, $b) => sprintf("%-26s%-8s\n", $a, $b),
str_split(implode(' ', str_split(bin2hex($string), 2)), 24),
str_split($string, 8)
));
【讨论】:
虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。以上是关于如何在 PHP 中获取字符串的十六进制转储?的主要内容,如果未能解决你的问题,请参考以下文章