Как я могу получить шестнадцатеричный дамп строки в PHP? - PullRequest
62 голосов
/ 29 июня 2009

Я изучаю кодировки в PHP5. Есть ли какой-нибудь способ получить необработанный шестнадцатеричный дамп строки? то есть шестнадцатеричное представление каждого байта (не символов) в строке?

Ответы [ 5 ]

91 голосов
/ 29 июня 2009
echo bin2hex($string);

или

for ($i = 0; $i < strlen($string); $i++) {
    echo str_pad(dechex(ord($string[$i])), 2, '0', STR_PAD_LEFT);
}

$string - переменная, содержащая ввод.

80 голосов
/ 19 ноября 2010

Для отладки работы с бинарными протоколами мне понадобился более традиционный дамп 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/>", если вам нужно отобразить вывод в браузере.

Надеюсь, это полезно: -)

5 голосов
/ 15 декабря 2015

Спустя годы, но в случае, если другие тоже ищут это, я позволил себе изменить код mindplay.dk, чтобы он принимал различные опции и моделировал вывод файла BSD hexdump -C:

<code>/**
* 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 = '.'
* 
* * @param string $ string * @param array $ options * @param string | array * / function hex_dump ($ string, array $ options = null) { if (! is_scalar ($ string)) { бросить новое InvalidArgumentException («аргумент $ 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']: '.'; # отступы для нечитаемых символов $ 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 как $ 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('/^\d{1,9}$/', $argv[2]) ? intval($argv[2]) : null;
        $len    = isset($argv[3]) && preg_match('/^\d{1,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);
    }
}
3 голосов
/ 29 ноября 2012

При отладке бинарного протокола мне также понадобился hexdump (). Я решил опубликовать свое решение в виде пакета PEAR, поскольку оно определенно полезно. Вы также можете просмотреть код на github.

ГРУША: http://www.metashock.de/pear

GitHub: http://www.github.com/metashock/Hexdump

В дополнение к решению mindplays он поддерживает улучшенный рендеринг последней строки и дополнительных параметров. Также пакет содержит исполняемый файл php с именем phphd для hexdumps на cmdline. Это может быть полезно в системах Windows:)

@mindplay.dk: Спасибо за идею strtr (). Это оказалось немного быстрее, чем моя предыдущая попытка. Интегрировал это в мою версию. (Использование уменьшенного буфера перевода) ..

Веселись!

1 голос
/ 18 декабря 2014

«Функциональная» версия:

$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))));

Заимствование из комментария Иону Г. Стэна , последняя строка может выглядеть следующим образом:

}, array_map('dechex', array_map('ord', str_split($s)))));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...