Преобразовать строку в двоичный файл, а затем снова использовать PHP
Есть ли способ преобразовать строку в двоичный файл, а затем снова вернуться в стандартную библиотеку PHP?
Чтобы уточнить, что я пытаюсь сделать, это сохранить пароль в базе данных. Я собираюсь сначала преобразовать его с помощью хэш-функции, а затем в конечном итоге сохранить в двоичном виде.
Я нашел лучший способ использовать эту функцию. Кажется, хэш и вывод в двоичном виде одновременно.
11 ответов
Вы хотите использовать 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));
Да, конечно!
Там...
$bin = decbin(ord($char));
... и обратно
$char = chr(bindec($bin));
Строка - это просто последовательность байтов, следовательно, это фактически двоичные данные в PHP. Что именно ты пытаешься сделать?
РЕДАКТИРОВАТЬ
Если вы хотите хранить двоичные данные в вашей базе данных, чаще всего проблема заключается в определении столбца в вашей базе данных. PHP не различает двоичные данные и строки, но базы данных делают. В MySQL, например, вы должны хранить двоичные данные в BINARY
, VARBINARY
или же BLOB
колонны.
Другим вариантом будет base64_encode
свою строку PHP и сохранить ее в некоторых VARCHAR
или же TEXT
столбец в базе данных. Но имейте в виду, что длина строки увеличится, когда base64_encode
используется.
Ваш хэш уже бинарный и готов к использованию с вашей базой данных.
Однако вам необходимо преобразовать его в формат, ожидаемый определением столбца базы данных.
Любая строка в 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
Потому что это то же самое. "Преобразование" является излишним.
Самый простой способ, который я нашел, - конвертировать в HEX вместо строки. Если это работает для вас:
$hex = bin2hex($bin); // It will convert a binary data to its hex representation
$bin = pack("H*" , $hex); // It will convert a hex to binary
ИЛИ ЖЕ
$bin = hex2bin($hex); // Available only on PHP 5.4
Я бы определенно рекомендовал использовать встроенные стандартные библиотеки паролей, которые поставляются с 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
Для преобразования десятичных знаков в char/strings вы можете сделать это:
# 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
Строки в PHP всегда являются BLOB-объектами. Таким образом, вы можете использовать строку для хранения значения для вашей базы данных BLOB. Все эти базовые преобразования и прочее связаны с представлением этого BLOB.
Если вам нужно хорошее удобочитаемое представление вашего BLOB, то имеет смысл показать байты, которые он содержит, и, вероятно, использовать шестнадцатеричный, а не десятичный. Следовательно, строка "41 42 43" - это хороший способ представить массив байтов, который в C# был бы
var bytes = new byte[] { 0x41, 0x42, 0x43 };
но это явно не хороший способ представить эти байты! Строка "ABC" является эффективным представлением, потому что на самом деле это тот же самый BLOB-объект (только в этом случае он не такой большой).
На практике вы обычно получаете свои большие двоичные объекты от функций, которые возвращают строку, таких как эта функция хеширования, или других встроенных функций, таких как fread.
В редких случаях (но не так редко, когда просто что-то пробуете / прототипируете), когда вам нужно просто создать строку из некоторых жестко закодированных байтов, я не знаю ничего более эффективного, чем преобразование "шестнадцатеричной строки" в то, что часто называют "двоичной строкой" в PHP:
$myBytes = "414243";
$data = pack('H*', $myBytes);
если ты var_dump($data);
это покажет вам string(3) "ABC"
, Это потому, что 0x41 = 65 decimal = 'A' (в основном во всех кодировках).
Поскольку просмотр двоичных данных путем интерпретации их как строки не совсем интуитивно понятен, вы можете захотеть сделать базовую оболочку, чтобы упростить отладку. Одна возможная такая обертка
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 и упаковать его в строку при взаимодействии с чем-то, что использует строки для двоичных данных. В зависимости от того, в какой степени вы на самом деле собираетесь модифицировать большой двоичный объект, это может оказаться проще, и, хотя он не занимает мало места, я думаю, вы получите приемлемую производительность для многих задач.
Пример для иллюстрации функциональности:
// 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";
Любой, кто будет здесь в 2021 году, может использовать ответ SteeveDroz ; но, к сожалению, это только для 1 персонажа. Поэтому я помещаю его в цикл for, чтобы просмотреть и изменить каждый символ строки.
РЕДАКТИРОВАТЬ: я только что понял, что созданная мной функция binary_encode НЕ превращает символы в 8 бит (что очень важно), она превращает их в 6-7 бит, но, к счастью, все, что мне нужно было сделать, это добавить к ним дополнительные 0, необходимые для создания это 8-битный. Я обновил функцию кодирования ниже. Также мне не нужно было исправлять функцию декодирования, так как она работает с добавленными 0 и без :)
Функции (обновлено):
function binaryEncode($str){
# Declare both Binary variable and Prepend variable
$bin = (string)""; $prep = (string)"";
# Iterate through each character of our input ($str)
for($i = 0; $i < strlen($str); $i++){
# Encode The current character into binary
$bincur = decbin( ord( $str[$i] ) );
# Count the length of said binary
$binlen = strlen( $bincur );
# If the length of our character in binary is less than a byte (8 bits); Then
# For how ever many characters it is short;
# it will replace with 0's in our Prepend variable.
if( $binlen < 8 ) for( $j = 8; $j > $binlen; $binlen++ ) $prep .= "0";
# Build our correct 8 bit string and add it to our Binary variable
$bin .= $prep.$bincur." ";
# Clear our Prepend variable before the next Loop
$prep = "";
}
# Return the final result minus the one whitespace at the end
# (from our for loop where we build the 8 bit string
return substr($bin, 0, strlen($bin) - 1);
}
function binary_decode($bin){
$char = explode(' ', $bin);
$nstr = '';
foreach($char as $ch) $nstr .= chr(bindec($ch));
return $nstr;
}
Использование:
$bin = binary_encode("String Here");
$str = binary_decode("1010011 1110100 1110010 1101001 1101110 1100111 100000 1001000 1100101 1110010 1100101");
Старая живая демонстрация:
http://sandbox.onlinephpfunctions.com/code/2553fc9e26c5148fddbb3486091d119aa59ae464
Новая живая демонстрация:
http://sandbox.onlinephpfunctions.com/code/1d71888cd41371646431f9914ccd86cf5ef6303e
Я искал преобразование битов строки и получил здесь, если следующий случай для вас, возьмите // это так... если вы хотите использовать биты из строки в разные биты, возможно, этот пример поможет
$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
Забавно, как Стефан Гериг, его ответ на самом деле правильный. Вам не нужно преобразовывать строку в строку "011010101", чтобы сохранить ее в поле BINARY в базе данных. Во всяком случае, так как это первый ответ, который появляется, когда вы гуглите "php преобразовать строку в двоичную строку". Вот мой вклад в эту проблему.
Ответ Франсуа Дешена, получивший наибольшее количество голосов, идет не так для длинных строк (либо байтовых, либо битовых), потому что
base_convert() может потерять точность при больших числах из-за свойств, связанных с используемым внутренним типом "double" или "float". Пожалуйста, смотрите раздел чисел с плавающей точкой в руководстве для получения более конкретной информации и ограничений.
От: 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"), вы не сможете восстановить исходную цепочку битов при преобразовании в строку байтов. Из обратного преобразования байтовой строки вы получите "00000101", который численно такой же (8-разрядное целое число без знака), но имеет другую длину строки. Поэтому, если для вас важна длина цепочки битов, вы должны сохранить длину в отдельной переменной и порезать первую часть строки после преобразования.
$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
Почему вы используете PHP для преобразования. Сейчас доступно так много языков интерфейса, почему вы все еще включаете сервер? Вы можете преобразовать пароль в двоичное число во внешнем интерфейсе и отправить преобразованную строку в базу данных. С моей точки зрения, это было бы удобно.
var bintext, textresult="", binlength;
this.aaa = this.text_value;
bintext = this.aaa.replace(/[^01]/g, "");
binlength = bintext.length-(bintext.length%8);
for(var z=0; z<binlength; z=z+8) {
textresult += String.fromCharCode(parseInt(bintext.substr(z,8),2));
this.ans = textresult;
Это код Javascript, который я нашел здесь: http://binarytotext.net/, они использовали этот код с Vue.js. В коде this.aaa - это динамическое значение v-модели. Чтобы преобразовать двоичный код в текстовые значения, они использовали большие числа. Вам необходимо установить дополнительный пакет и преобразовать его обратно в текстовое поле. На мой взгляд, это было бы легко.