2009-06-29 4 views
55

Sto esaminando le codifiche in PHP5. C'è un modo per ottenere un dump esadecimale grezzo di una stringa? cioè una rappresentazione esadecimale di ciascuno dei byte (non dei caratteri) in una stringa?Come posso ottenere un dump esadecimale di una stringa in PHP?

+1

alcuni piccoli strumento online http://srsbiz.pl/utils/hexit .php ed è php source: gist.github.it/4639219 - potrebbe essere utile, crediti/grazie @ dev-null-dweller – hakre

+0

https://github.com/clue/php-hexdump – bishop

risposta

80
echo bin2hex($string); 

o:

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

$string è la variabile che contiene ingresso.

+12

O un approccio più funzionale: print_r (array_map ('dechex', array_map ('ord', str_split ($ string)))); –

66

Per il debug di lavoro con i protocolli binari, ho bisogno di un più tradizionale discarica HEX, così ho scritto questa funzione:

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; 
    } 
} 

Questo produce una più tradizionale discarica HEX, in questo modo:

hex_dump($data); 

=> 

0 : 05 07 00 00 00 64 65 66 61 75 6c 74 40 00 00 00 [[email protected]] 
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] 

Tieni presente che i caratteri non visibili vengono sostituiti da un punto: puoi modificare il numero di byte per riga (larghezza $) e il carattere di riempimento ($ pad) in base alle tue esigenze. Ho incluso un argomento $ newline, quindi è possibile passare "<br/>" se è necessario visualizzare l'output in un browser.

Spero che questo è utile :-)

+2

+1 eccellente. Troppo eccellente Ho lavorato su quattro ore + su qualcosa e questo mi ha semplicemente stimolato. Ad ogni modo, ho scoperto che l'eco di un tag pre lo rende migliore in un browser. O usando br newline. Sono nuovo di questo e mi chiedo come posso decifrare i caratteri non visibili. TNX. – frostymarvelous

+0

Love it! Ha bisogno di un paio di miglioramenti, ma come base dello strumento di debug - è perfetto! –

+2

@frostymarvelous per l'output diagnostico di solo testo in un browser, prova 'header ('Content-type: text/plain');' - è utile :-) –

3

Mentre il debug di un protocollo binario avevo bisogno di una hexdump() troppo. Ho deciso di pubblicare la mia soluzione come pacchetto PEAR in quanto è decisamente utile. Puoi anche sfogliare il codice su github.

PEAR: http://www.metashock.de/pear

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

Oltre alla soluzione mindplays supporta il rendering Propper dell'ultima riga e params aggiuntivi. Anche il pacchetto contiene un eseguibile PHP chiamato phphd per hexdumps su cmdline. Questo potrebbe essere utile su Sistemi Windows :)

@ mindplay.dk: Grazie per l'idea strtr(). Sembrava leggermente più veloce del mio precedente tentativo. Integrato nella mia versione. (Utilizzando un buffer di traduzione diminuito) ..

Buon divertimento!

1

versione "funzionale":

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

Prendendo in prestito da Ionuţ G. Stan comment, l'ultima riga potrebbe essere il seguente:

}, array_map('dechex', array_map('ord', str_split($s))))); 
4

E 'anni dopo, ma nel caso in cui gli altri sono alla ricerca di anche questo mi sono preso la libertà di modificare il codice di mindplay.dk per far sì che accetti varie opzioni e simuli l'output del comando BSD hexdump -C file:

/** 
* 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; 
} 

e questo è una discarica esadecimale di un piccolo file:

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 

e questo è la prova 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); 
    } 
} 
+0

L'ultima riga 00000086 è inutile. –

+3

Dillo che all'autore del comando BSD hexdump. L'ultima riga indica la dimensione del file. –