How can I get a hex dump of a string in PHP?

PhpStringEncodingCharacter EncodingHex

Php Problem Overview


I'm investigating encodings in PHP5. Is there some way to get a raw hex dump of a string? i.e. a hex representation of each of the bytes (not characters) in a string?

Php Solutions


Solution 1 - Php

echo bin2hex($string);

or:

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

$string is the variable which contains input.

Solution 2 - Php

For debugging work with binary protocols, I needed a more traditional HEX dump, so I wrote this function:

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

This produces a more traditional HEX dump, like this:

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]

Note that non-visible characters are replaced with a period - you can change the number of bytes per line ($width) and padding character ($pad) to suit your needs. I included a $newline argument, so you can pass "<br/>" if you need to display the output in a browser.

Solution 3 - Php

It's years later, but in case others are searching for this too, I took the liberty to modify mindplay.dk's code to make it accept various options and simulate the output of the BSD command 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;
}

and this is a hex dump of a small 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

and this is the phpunit test:

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

Solution 4 - Php

While debugging a binary protocol I needed a hexdump() too. I decided to publish my solution as a PEAR package as it's definitely useful. You can also browse the code at github.

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

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

In addition to mindplays solution it supports propper rendering of the last line and additional params. Also the package contains a php executable named phphd for hexdumps on cmdline. This might be helpful on Windows Systems :)

@mindplay.dk : Thanks for the strtr() idea. It appeared slight faster than my former attempt. Integrated that into my version. (Using a decreased translation buffer)..

Solution 5 - Php

"Functional" version:

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

Borrowing from Ionuț G. Stan's comment, the last line might be as follows:

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

Solution 6 - Php

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAmandasaurusView Question on Stackoverflow
Solution 1 - PhpStefan GehrigView Answer on Stackoverflow
Solution 2 - Phpmindplay.dkView Answer on Stackoverflow
Solution 3 - PhpInternal Server ErrorView Answer on Stackoverflow
Solution 4 - Phphek2mglView Answer on Stackoverflow
Solution 5 - Phpx-yuriView Answer on Stackoverflow
Solution 6 - Phpuser13104741View Answer on Stackoverflow