web-dev-qa-db-fra.com

Convertir une chaîne en binaire puis revenir en utilisant PHP

Existe-t-il un moyen de convertir une chaîne en binaire puis de revenir dans la bibliothèque standard PHP?

Pour clarifier ce que j'essaie de faire, c'est de stocker un mot de passe dans une base de données. Je vais d'abord le convertir en utilisant une fonction de hachage, puis le stocker en binaire.


J'ai trouvé le meilleur moyen d'utiliser cette fonction. Semble hacher et sortir en binaire en même temps.

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

46
locoboy

Vous voulez utiliser pack et 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
Francois Deschenes

Oui bien sûr!

Là...

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

... et retour.

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

Une chaîne de caractères n'est qu'une séquence d'octets, c'est donc une donnée binaire en PHP. Qu'est-ce que vous essayez de faire exactement?

MODIFIER

Si vous souhaitez stocker des données binaires dans votre base de données, le problème le plus souvent est la définition de colonne dans votre base de données. PHP ne différencie pas les données binaires des chaînes, mais les bases de données le font. Dans MySQL, par exemple, vous devez stocker des données binaires dans BINARY, VARBINARY ou BLOB columns. 

Une autre option serait de base64_encode votre chaîne PHP et de la stocker dans une colonne VARCHAR ou TEXT de la base de données. Mais sachez que la longueur de la chaîne augmentera lorsque base64_encode est utilisé.

9
Stefan Gehrig

le moyen le plus simple que j'ai trouvé était de convertir en HEX au lieu d'une chaîne. Si cela fonctionne pour vous:

$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

Votre hash est déjà binaire et prêt à être utilisé avec votre base de données.

Cependant, vous devez le convertir dans un format attendu par la définition de colonne de base de données.

Toute chaîne dans PHP (jusqu'à la version 5.3) est une chaîne binaire. Cela signifie qu'il ne contient que des données binaires. 

Cependant, à cause de la compatibilité avec PHP 6, vous pouvez déjà convertir explicitement votre chaîne en binaire:

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

Mais ceci est simplement pour des raisons de compatibilité, dans votre code, vous pouvez simplement faire:

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

Parce que c'est pareil. Le "converti" est superflu.

3
hakre

C'est drôle comment Stefan Gehrig sa réponse est en fait la bonne. Vous n'avez pas besoin de convertir une chaîne en chaîne "011010101" pour la stocker dans le champ BINARY d'une base de données. Quoi qu’il en soit, c’est la première réponse qui apparaît lorsque vous recherchez Google pour "php convertir une chaîne en chaîne binaire". Voici ma contribution à ce problème.

La réponse la plus votée de François Deschenes se passe mal pour les longues chaînes (bytestrings ou bitstrings) car

base_convert () peut perdre de la précision sur les grands nombres en raison de propriétés liées au type interne "double" ou "float" utilisé. Veuillez vous reporter à la section Numéros en virgule flottante du manuel pour des informations plus spécifiques et leurs limitations.

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

Pour contourner cette limitation, vous pouvez découper la chaîne d'entrée en fragments. Les fonctions ci-dessous implémentent cette technique.

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

Notez que si vous insérez une chaîne de bits qui n'est pas une multitude de 8 (exemple: "101"), vous ne pourrez pas récupérer la chaîne de bits d'origine lors de la conversion en chaîne bytestring. A partir de la conversion de la bytestring, vous obtiendrez "00000101" qui est numériquement identique (entier non signé de 8 bits) mais dont la longueur de chaîne est différente. Par conséquent, si la longueur de la chaîne de bits est importante pour vous, vous devez la sauvegarder dans une variable distincte et hacher la première partie de la chaîne après la conversion.

$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

je cherchais une conversion de bits de chaîne et je suis arrivé ici, Si le cas suivant vous concerne, prenez-le donc ... ... si vous voulez utiliser les bits d'une chaîne de caractères dans différents bits. peut-être que cet exemple aiderait

$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

Les chaînes entre PHP sont toujours des BLOBs. Vous pouvez donc utiliser une chaîne pour contenir la valeur de votre BLOB de base de données. Toutes ces opérations de conversion de base, etc., ont à voir avec {présentation} _ ce BLOB.

Si vous voulez une belle représentation lisible par l’homme de votre BLOB, il est judicieux de montrer les octets qu’il contient, et probablement d’utiliser le format hexadécimal plutôt que décimal. Par conséquent, la chaîne "41 42 43" est un bon moyen de présenter le tableau d'octets qui, en C #, serait 

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

mais c’est évidemment pas un bon moyen de représenter ces octets! La chaîne "ABC" est une représentation efficace, car il s'agit en fait du même BLOB (sauf que ce n'est pas si grand dans ce cas). 

En pratique, vous obtiendrez généralement vos objets BLOB à partir de fonctions renvoyant des chaînes, telles que la fonction de hachage, ou d’autres fonctions intégrées telles que fread .

Dans les rares cas (mais pas si rares lors d'essais ou de prototypage) qu'il vous suffit de construire une chaîne à partir d'octets codés en dur, je ne connais rien de plus efficace que de convertir une "chaîne hexagonale" en souvent appelée "chaîne binaire" en PHP:

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

Si vous var_dump($data);, il vous montrera string(3) "ABC". En effet, 0x41 = 65 décimal = 'A' (dans pratiquement tous les codages). 

Etant donné que regarder des données binaires en les interprétant comme une chaîne n’est pas vraiment intuitif, vous pouvez créer un wrapper de base pour faciliter le débogage. Un tel emballage est possible

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

C’est quelque chose que j’ai concocté à la volée et c’est probablement un point de départ pour votre propre emballage. Mais l’idée est d’utiliser une chaîne pour le stockage car il s’agit de la structure la plus efficace disponible en PHP, tout en fournissant des méthodes telles que toArray () à utiliser dans les contrôles/évaluations du débogueur lorsque vous souhaitez examiner le contenu. 

Bien sûr, vous pouvez utiliser un tableau parfaitement simple PHP à la place et le compresser dans une chaîne lors de l'interfaçage avec quelque chose utilisant des chaînes pour les données binaires. En fonction du degré auquel vous allez réellement modifier le blob, cela peut s'avérer plus facile et, même s'il n'est pas peu encombrant, je pense que vous obtiendrez des performances acceptables pour de nombreuses tâches.

Un exemple pour illustrer la fonctionnalité:

// 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