web-dev-qa-db-ja.com

文字列をバイナリに変換してから、PHP

文字列をバイナリに変換してから標準のPHPライブラリに戻す方法はありますか?

私がやろうとしていることを明確にするために、パスワードをデータベースに保存します。最初にハッシュ関数を使用して変換し、最終的にバイナリとして保存します。


この関数を使用するのが最善の方法であることがわかりました。ハッシュとバイナリの出力を同時に行うようです。

http://php.net/manual/en/function.hash-hmac.php

48
locoboy

pack および base_convert

// Convert a string into binary
// Should output: 0101001101110100011000010110001101101011
$value = unpack('H*', "Stack");
echo base_convert($value[1], 16, 2);

// Convert binary into a string
// Should output: Stack
echo pack('H*', base_convert('0101001101110100011000010110001101101011', 2, 16));
50

はい、そうです!

そこ...

$bin = decbin(ord($char));

...そして再び。

$char = chr(bindec($bin));
29
SteeveDroz

文字列は単なるバイトのシーケンスであるため、実際にはPHPのバイナリデータです。正確に何をしようとしていますか?

[〜#〜] edit [〜#〜]

データベースにバイナリデータを格納する場合、ほとんどの場合、問題はデータベースの列定義です。 PHPはバイナリデータと文字列を区別しませんが、データベースは区別します。MySQLでは、バイナリデータを BINARYVARBINARY または BLOB 列。

別のオプションはbase64_encode your PHP stringで、データベースのVARCHARまたはTEXT列に格納します。ただし、base64_encode 使用されている。

9
Stefan Gehrig

私が見つけた最も簡単な方法は、文字列ではなく16進数に変換することでした。それがあなたのために働くなら:

$hex = bin2hex($bin); // It will convert a binary data to its hex representation

$bin = pack("H*" , $hex); // It will convert a hex to binary

OR

$bin = hex2bin($hex); // Available only on PHP 5.4
4
Regis Camimura

ハッシュはすでにバイナリであり、データベースで使用する準備ができています。

ただし、データベース列の定義が期待する形式に変換する必要があります。

PHP(5.3まで)の文字列はすべてバイナリ文字列です。つまり、バイナリデータのみが含まれています。

ただし、PHP 6との後方互換性のため、すでにバイナリとして文字列を明示的にキャストできます。

 $string = 'my binary string';
 $binary = b'my binary string';

しかし、それは単に互換性の理由のためであり、あなたのコードであなたがすることができます:

  $string = $binary; // "convert" binary string into string
  $binary = $string  // "convert" string into binary string

同じだから。 「変換」は不要です。

3
hakre

PHPに付属 --ここに良い例があります それらの使い方について。


ここに来て、バイナリ文字列から小数に戻る方法を理解するために、以下にいくつかの良い例を示します。

バイナリの「文字列」を小数/文字に変換するには、次のようなことができます...

echo bindec("00000001") . "\n";
echo bindec("00000010") . "\n";
echo bindec("00000100") . "\n";
echo bindec("00001000") . "\n";
echo bindec("00010000") . "\n";
echo bindec("00100000") . "\n";
echo bindec("01000000") . "\n";
echo bindec("10000000") . "\n";
echo bindec("01000001") . "\n";

# big binary string
echo bindec("111010110111011110000110001")."\n";

上記の出力:

1
2
4
8
16
32
64
128
65
123452465

小数を文字/文字列に変換するには、これを行うことができます:

# convert to binary strings "00000001"
echo decbin(1) . "\n";
echo decbin(2) . "\n";
echo decbin(4) . "\n";
echo decbin(8) . "\n";
echo decbin(16) . "\n";
echo decbin(32) . "\n";
echo decbin(64) . "\n";
echo decbin(128) . "\n";

# convert a ascii character
echo str_pad(decbin(65), 8, 0, STR_PAD_LEFT) ."\n";

# convert a 'char'
echo str_pad(decbin(ord('A')), 8, 0, STR_PAD_LEFT) ."\n";

# big number...
echo str_pad(decbin(65535), 8, 0, STR_PAD_LEFT) ."\n";
echo str_pad(decbin(123452465), 8, 0, STR_PAD_LEFT) ."\n";

上記の出力:

1
10
100
1000
10000
100000
1000000
10000000
01000001
01000001
1111111111111111
111010110111011110000110001
0
MichaelICE

ステファン・ゲーリッグの答えが実際に正しいものであることがおかしいです。データベースのBINARYフィールドに格納するために、文字列を「011010101」文字列に変換する必要はありません。とにかく、これは「phpが文字列をバイナリ文字列に変換する」ことをグーグルで検索するときに最初に出てくる答えなので、これがこの問題への私の貢献です。

Francois Deschenesによる最も投票された回答は、長い文字列(バイト文字列またはビット文字列)に対して間違っています。

base_convert()は、使用される内部の「double」または「float」型に関連するプロパティのために、大きな数値では精度を失う場合があります。より具体的な情報と制限については、マニュアルの「浮動小数点数」セクションを参照してください。

From: https://secure.php.net/manual/en/function.base-convert.php

この制限を回避するには、入力文字列をチャンクに分割します。以下の関数はこのテクニックを実装しています。

<?php

function bytesToBits(string $bytestring) {
  if ($bytestring === '') return '';

  $bitstring = '';
  foreach (str_split($bytestring, 4) as $chunk) {
    $bitstring .= str_pad(base_convert(unpack('H*', $chunk)[1], 16, 2), strlen($chunk) * 8, '0', STR_PAD_LEFT);
  }

  return $bitstring;
}

function bitsToBytes(string $bitstring) {
  if ($bitstring === '') return '';

  // We want all bits to be right-aligned
  $bitstring_len = strlen($bitstring);
  if ($bitstring_len % 8 > 0) {
    $bitstring = str_pad($bitstring, intdiv($bitstring_len + 8, 8) * 8, '0', STR_PAD_LEFT);
  }

  $bytestring = '';
  foreach (str_split($bitstring, 32) as $chunk) {
    $bytestring .= pack('H*', str_pad(base_convert($chunk, 2, 16), strlen($chunk) / 4, '0', STR_PAD_LEFT));
  }

  return $bytestring;
}

for ($i = 0; $i < 10000; $i++) {
  $bytestring_in = substr(hash('sha512', uniqid('', true)), 0, Rand(0, 128));
  $bits = bytesToBits($bytestring_in);
  $bytestring_out = bitsToBytes($bits);
  if ($bytestring_in !== $bytestring_out) {
    printf("IN  : %s\n", $bytestring_in);
    printf("BITS: %s\n", $bits);
    printf("OUT : %s\n", $bytestring_out);
    var_dump($bytestring_in, $bytestring_out); // printf() doesn't show some characters ..
    die('Error in functions [1].');
  }
}


for ($i = 0; $i < 10000; $i++) {
  $len = Rand(0, 128);
  $bitstring_in = '';
  for ($j = 0; $j <= $len; $j++) {
    $bitstring_in .= (string) Rand(0,1);
  }
  $bytes = bitsToBytes($bitstring_in);
  $bitstring_out = bytesToBits($bytes);

  // since converting to byte we always have a multitude of 4, so we need to correct the bitstring_in to compare ..
  $bitstring_in_old = $bitstring_in;
  $bitstring_in_len = strlen($bitstring_in);
  if ($bitstring_in_len % 8 > 0) {
    $bitstring_in = str_pad($bitstring_in, intdiv($bitstring_in_len + 8, 8) * 8, '0', STR_PAD_LEFT);
  }

  if ($bitstring_in !== $bitstring_out) {
    printf("IN1  : %s\n", $bitstring_in_old);
    printf("IN2  : %s\n", $bitstring_in);
    printf("BYTES: %s\n", $bytes);
    printf("OUT  : %s\n", $bitstring_out);
    var_dump($bytes); // printf() doesn't show some characters ..
    die('Error in functions [2].');
  }
}

echo 'All ok!' . PHP_EOL;

8の倍数ではないビット文字列(例:「101」)を挿入すると、バイト文字列に変換したときに元のビット文字列を復元できないことに注意してください。バイト文字列を元に戻すと、数値的には同じ(符号なし8ビット整数)で文字列の長さが異なる「00000101」が返されます。そのため、ビット文字列の長さが重要な場合は、長さを別の変数に保存し、変換後の文字列の最初の部分をチョップする必要があります。

$bits_in = "101";
$bits_in_len = strlen($bits_in); // <-- keep track if input length
$bits_out = bytesToBits(bitsToBytes("101"));
var_dump($bits_in, $bits_out, substr($bits_out, - $bits_in_len)); // recover original length with substr
0
Flip

私はいくつかの文字列ビット変換を探していて、ここに来ました、次の場合は// itそうです...文字列のビットを別のビットに使用したい場合は、この例が役立つかもしれません

$string="1001"; //this would be 2^0*1+....0...+2^3*1=1+8=9
$bit4=$string[0];//1
$bit3=$string[1];
$bit2=$string[2];
$bit1=$string[3];//1
0
shoetrax

PHPの文字列は常にBLOBです。データベースのBLOBの値を保持するために文字列を使用できます。これらすべてのベース変換などはそのBLOBを表す

人間が読めるBLOBの表現が必要な場合は、BLOBに含まれるバイトを表示し、おそらく10進数ではなく16進数を使用するのが理にかなっています。したがって、文字列「41 42 43」は、C#でのバイト配列をpresentにする良い方法です。

_var bytes = new byte[] { 0x41, 0x42, 0x43 };
_

しかし、明らかにnotそれらのバイトをrepresentする良い方法です!文字列「ABC」は、実際には同じBLOBであるため、効率的な表現です(この場合は、それほど大きくありません)。

実際には、通常、ハッシュ関数などの文字列を返す関数、または fread などの他の組み込み関数からBLOBを取得します。

ハードコードされたバイトから文字列を構築する必要があるまれな場合(ただし、物事を試す/プロトタイピングするときはそれほどまれではない)、「16進文字列」をPHPでは「バイナリ文字列」と呼ばれることがよくあります。

_$myBytes = "414243";
$data = pack('H*', $myBytes);
_

var_dump($data);の場合、string(3) "ABC"が表示されます。これは、0x41 = 65 decimal = 'A'(基本的にすべてのエンコーディング)のためです。

バイナリデータを文字列として解釈して見ることは正確には直観的ではないため、デバッグを容易にするために基本的なラッパーを作成することができます。可能なラッパーの1つは

_class blob
{
    function __construct($hexStr = '')
    {
        $this->appendHex($hexStr);
    }

    public $value;

    public function appendHex($hexStr)
    {
        $this->value .= pack('H*', $hexStr);
    }

    public function getByte($index)
    {
        return unpack('C', $this->value{$index})[1];
    }

    public function setByte($index, $value)
    {
        $this->value{$index} = pack('C', $value);
    }

    public function toArray()
    {
        return unpack('C*', $this->value);
    }
}
_

これは私がその場で作り上げたもので、おそらくあなた自身のラッパーの出発点にすぎません。ただし、これはPHPで利用可能な最も効率的な構造であるため、ストレージに文字列を使用することです。また、内容を調べたいときにデバッガーの監視/評価で使用するtoArray()などのメソッドを提供します.

もちろん、代わりに完全に単純なPHP配列を使用して、バイナリデータに文字列を使用するものとインターフェイスするときに文字列にパックすることができます。実際に変更する度合いに応じてblobこれは簡単かもしれませんが、スペース効率は良くありませんが、多くのタスクで十分なパフォーマンスが得られると思います。

機能を説明する例:

_// Construct a blob with 3 bytes: 0x41 0x42 0x43.
$b = new blob("414243");

// Append 3 more bytes: 0x44 0x45 0x46.
$b->appendHex("444546");

// Change the second byte to 0x41 (so we now have 0x41 0x41 0x43 0x44 0x45 0x46).
$b->setByte(1, 0x41); // or, equivalently, setByte(1, 65)

// Dump the first byte.
var_dump($b->getByte(0));

// Verify the result. The string "AACDEF", because it's only ASCII characters, will have the same binary representation in basically any encoding.
$ok = $b->value == "AACDEF";
_
0
Dojo