Thursday 19 October 2017

0x47 Binary Options


Manejo de datos binarios en PHP con pack () y descomprimir () Warning. Esta publicación ha sido publicada hace más de dos años. Eso es mucho tiempo en el mundo del desarrollo La historia aquí puede no ser relevante, completa o segura. El código puede no ser completo u obsoleto, e incluso mi visión actual podría haber cambiado (completamente) en el tema. Por favor, lea más, pero úselo con precaución. Hoy en día la mayoría de la funcionalidad de bajo nivel como la lectura o escritura de gráficos se cuidan de bibliotecas de terceros y eso está bien. Su forma complicada de hacer las cosas bien y es probable que desee centrarse en la salida o el envío de un PNG en lugar de una construcción desde cero. Mientras que la lectura y la escritura de este tipo de datos binarios se hizo normalmente en idiomas como C o incluso ensamblador, la mayoría de los lenguajes de nivel superior todavía tienen estas capacidades y sí, incluso PHP Meet pack () y unpack (). La mayoría de la gente ni siquiera quiere saber cómo se hacen las cosas internamente y ni siquiera quieren saber cómo se ve una bola de alquitrán, o cómo un archivo PNG almacena sus paletas de colores. Sin embargo, si usted es como yo, entonces usted es lo suficientemente curioso y quiere saber. Así que hoy voy a mostrar cómo leer un archivo PNG directamente desde el disco y mostrar la información que se esconde detrás de la imagen. Incluso podría decirle un truco de optimización o dos en el ínterin :-) Primero lo primero: pack () y unpack (). Cuando se trata de datos binarios en PHP hay 2 funciones principales que no se puede vivir sin. Las funciones pack () y unpack () toman una cadena (binaria) y las convierten en una matriz. Ambos trabajan más o menos de la misma manera. Pack () almacenará una matriz en una estructura binaria, mientras que unpack () hará lo contrario. Si escribiera binarystring a un archivo, sería de 8 bytes de longitud: 4 bytes para la longitud (ya que es un valor de 32 bits), 3 bytes para el ascii aBc, 1 byte para cr y 1 byte para lf Con desempaquetar tiene que Agregue la clave ya que la salida es una matriz asociativa. Echa un vistazo en el manual de php para obtener más información acerca de pack () / unpack (). Formato PNG: El formato binario para archivos PNG está disponible en Internet. Al ver un archivo PNG en un visor hexadecimal o editor, verá que los primeros 8 bytes son siempre los mismos. El primer byte siempre es 0x89. De segundo a cuarto byte son las letras PNG (o en hexadecimal: 0x50 0x4E 0x47) 5º y 6º son los bytes 0x0d y 0x0a, lo que representa una línea DOS terminando 7º y 8º bytes son 0x1a y 0x0a Así que para comprobar si un archivo es Un PNG válido, debemos hacer lo siguiente: abrir el archivo (como binario) leer los primeros 8 bytes descomprimir los bytes comprobar si todas las entradas son lo que esperamos abrir el archivo (como binario): observe la b en las opciones de archivo. Esto asegurará que el archivo se abre en modo binario. Lea los primeros 8 bytes: los datos contendrán una cadena binaria. No se puede leer realmente, por lo que tenemos que descomprimir los datos de ella: Esto crearía una matriz de encabezado con la siguiente información: como se puede ver, la primera entrada (highbit) es 137, que es el mismo que 0x89. La firma es una cadena normal con PNG y otros caracteres deben ser los mismos que los anteriores. Como ejemplo, comprueba si el highbit es realmente 0x89 y comprueba la singnature para PNG. Debe comprobar los demás también. Después de la cabecera PNG, obtiene bloques de datos llamados trozos. Cada trozo se formatea de la misma manera: 4 bytes. Longitud del trozo 4 bytes. Tipo de trozo N bytes. Datos de trozos 4 bytes. Chunk CRC Antes de leer los datos del trozo, debemos leer la longitud del trozo. Así que lo primero que hacemos es leer los primeros 8 bytes (o 2 dwords en realidad): Ahora el número de bytes de datos son conocidos para que podamos leerlos también: finalmente: leemos el código CRC y lo añadimos a la matriz chunk: Reading Todos los trozos Cuando lees un trozo, puedes leerlos todos. Dependiendo del tipo de chunk, realmente puede desempacar los datos y mostrar o utilizar esa información también. Optimización Te dije que estaba compartiendo un truco de optimización en el principio. Así que aquí está: Como usted pudo haber visto, PNGs tienen un montón de trozos adicionales con ellos. Incluyendo cosas como la última vez que fue escrito y un montón de trozos de texto. Dado que estos trozos no son necesarios para mostrar el PNG correctamente, y sólo ocupan espacio, puede escribir un programa que elimina estos trozos del PNG. Esto es un truco que la mayoría de los compresores de imágenes usarán para lograr imágenes de menor tamaño sin cambiar ni siquiera un byte en la imagen real. Neat huh Capturas Los datos binarios se manejan de forma diferente dependiendo de la CPU. La mayoría de las CPUs hoy en día usan little-endian (intels x86 por ejemplo) pero todavía hay big-endian cpus por ahí (68000, etc powerpcs). Al leer una palabra o dword de datos binarios, asegúrese de saber en qué endian los datos se escriben de lo contrario podría terminar con datos incorrectos. Especialmente cuando desea escribir datos binarios, asegúrese de pensar en todo. Las cosas pueden ser muy complicadas y escribir mal un solo byte corromperá toda la imagen. Hay un montón de bibliotecas por ahí que pueden hacer estas cosas mucho mejor de lo que nunca. Pero eso no debería detenerte para intentar de todos modos :-) basE91 introducción de codificación basE91 es un método avanzado para codificar datos binarios como caracteres ASCII. Es similar a UUencode o base64, pero es más eficiente. La sobrecarga producida por basE91 depende de los datos de entrada. Se asciende como máximo a 23 (frente a 33 para base64) y puede variar hasta 14, lo que ocurre típicamente en bloques de 0 bytes. Esto hace que basE91 sea muy útil para transferir archivos más grandes a través de conexiones binarias no seguras como correo electrónico o líneas terminales. Alfabeto Como su nombre indica, basE91 necesita 91 caracteres para representar los datos binarios codificados en ASCII. A partir de los 94 caracteres ASCII imprimibles (0x21-0x7E), se han omitido los siguientes tres para construir el alfabeto basE91: La tabla de traducción se compone de los caracteres restantes como se muestra a continuación. Description Pack dio argumentos en una cadena binaria de acuerdo al formato. La idea para esta función se tomó de Perl y todos los códigos de formato funcionan igual que en Perl. Sin embargo, hay algunos códigos de formato que faltan como Perl039s quotuquot código de formato. Tenga en cuenta que la distinción entre valores firmados y no firmados sólo afecta a la función unpack (). Donde como function pack () da el mismo resultado para los códigos de formato firmados y sin firmar. Parámetros La cadena de formato consiste en códigos de formato seguidos por un argumento de repetidor opcional. El argumento repetidor puede ser un valor entero o repetirse al final de los datos de entrada. Para a, A, h, H el recuento de repetición especifica cuántos caracteres de un argumento de datos se toman, ya que es la posición absoluta donde poner los datos siguientes, para todo lo demás el recuento de repetición especifica cuántos argumentos de datos se consumen y empaquetan En la cadena binaria resultante. Los formatos actualmente implementados son: Una clase auxiliar para convertir entero a cadenas binarias y viceversa. Útil para escribir y leer enteros a / desde archivos o sockets. Clase inthelper public static function int8 (i) devuelve isint (i). Paquete (c. I). Desempaquetar (c. I) 1 función estática pública uInt8 (i) return isint (i). Paquete (C. i). Desempaquetar (C. i) 1 función estática pública int16 (i) return isint (i). Paquete (s) (i). Desempaquetar (s. I) 1 función estática pública uInt16 (i. Endianness false) f isint (i). paquete. Desempaquetar el espacio de retorno (i). I 1 I función estática pública int32 (i) return isint (i). Paquete (l, i). Desempaquetar (l. I) 1 función estática pública uInt32 (i. Endianness false) f isint (i). paquete. Desempaquetar el espacio de retorno (i). I 1 I función estática pública int64 (i) return isint (i). Paquete (q.1). Desempaquetar (q. I) 1 función estática pública uInt64 (i. Endianness false) f isint (i). paquete. Desempaquetar el espacio de retorno (i). I 1 I gt Ejemplo de uso: ltphp Header (Content-Type: text / plain) include (inthelper. php) echo inthelper. UInt8 (0x6b). PHPEOL // k eco inthelper. UInt8 (107). PHPEOL // k eco inthelper. UInt8 (x6b). PHPEOL. PHHEOL // 107 inthelper de eco. UInt16 (4101). PHPEOL // x05x10 inthelper de eco. UInt16 (x05x10). PHLEOL // 4101 inthelper de eco. UInt16 (x05x10. Verdadero). PHPEOL. PHPEOL // 1296 intercomunicador de eco. UInt32 (2147483647). PHPEOL // xffxffxffx7f echo inthelper. UInt32 (xffxffxffx7f). PHPEOL. PHPEOL // 2147483647 // Nota: prueba esto con la compilación de 64 bits de PHP echo inthelper. UInt64 (9223372036854775807). PHPEOL // xffxffxffxffxffxffxffx7f echo inthelper. UInt64 (xffxffxffxffxffxffxffx7f). PHPEOL. PHPEOL // 9223372036854775807 Ejemplo de codificadores es básicamente una explicación de bindec () y decbin (), no pack () y unpack (). Aquí hay código para convertir una expresión binaria de cadena en su equivalente de cadena binaria y viceversa. (Sería aún más simple si pack / unpack ofreciera el código de formato ab.) Función ltphp bin2bstr (entrada) // Convierte una expresión binaria (por ejemplo 100111) en una cadena binaria if (isstring (input)) devuelve null // Control de sanidad / / Pack en un paquete de retorno de cadena (H. baseconvert (entrada 2. 16)) función bstr2bin (entrada) // Representación binaria de una cadena binaria if (isstring (entrada)) return null // Comprobación de sanidad // Desempaquetar como Un valor de cadena hexadecimal unpack (entrada H.) // Retorno de representación binaria de salida baseconvert (valor 1, 16. 2) // Devuelve cadena (3) ABC vardump (bin2bstr (01000001 01000010 01000011)) // Devuelve string (24) 010000010100001001000011 Aunque en una arquitectura de 64 bits intval (6123456789) 6123456789, y sprintf (b, 5000000000) 100101010000001011111001000000000 paquete no tratará nada pasó a ella como de 64 bits. Si desea empacar un entero de 64 bits: ltphp grande 5000000000 a la izquierda 0xffffffff00000000 a la derecha 0x00000000ffffffff l (amplificador grande a la izquierda) gtgt 32 r amplificador grande derecho paquete bueno (NN l. R) urlsafe strreplace (matriz (./), array -), base64encode (good)) // reconstruir: unurl strreplace (array), array (./), urlsafe) binario base64decode (unurl) conjunto descomprimir (N2.tmp) printr (conjunto) conjunto original 1 ltlt 32 set 2 echo original. Rn gt resultados en: Array (1 gt 1 2 gt 705032704) 5000000000 pero SOLAMENTE en una máquina permitida 64-bit y PHP distro. Estas dos funciones permiten la conversión entre la cadena binaria y entero con signo con la posibilidad de dar la longitud de bits. Uso: ltphp eco si2bin (- 10. 32) 11111111111111111111111111110110 eco si2bin (10. 32) 00000000000000000000000000001010 eco bin2si (11111111111111111111111111110110. 32) - 10 de eco bin2si (00000000000000000000000000001010. 32) 10 // entero de que si2bin función binaria (si los bits 32. ) If (si gt - pow (2. bits - 1) y si lt pow (2. bits - 1)) si (si gt 0) // positivo o cero bin baseconvert Bits bits binlength strlen (bin) si (binlength lt bits) bin strrepeat (0. bits - binlength). Bin else // negativo si - si - pow (2. bits) bin baseconvert (si. 10.2) binlength strlen (bin) si (binlength gt bits) bin strrepeat (1. bits - binlength). Bin bin binario bin binario a signo entero bin2si (bin bits 32) if (bits strlen (bin)) si (substr (bin. 0. 1) 0) // positivo o cero si baseconvert (bin. ) else // si baseConvert negativo (bin 2. 10) si -. (pow (2. bits) - SI) de retorno si gt Esto es cómo solía paquete para convertir Base2 a base64 ya base 64 de soporte baseConvert duerma Las conversiones de base no funcionan Para las cadenas largas, por lo que convierto 1 byte a la vez Espero que esto ayude a alguien función base2to64 (base2) if (restbits strlen (base2) 8) base2. Strrepeat (0,8-permanece) base64 NULL para (i0iltstrlen (base2) i8) base16. sprintf (02x, bindec (sprintf (08d, substr (Base2, i, 8)))) de retorno base64encode (paquete (H, Base16)) Función base64to2 lista (base 64) (Base16) Abrir con (H0, base64decode (base 64)) Base2 NULL para (i0iltstrlen (base16) i) base2. Sprintf (04d, baseconvert (substr (base16, i, 1), 16,2)) return base2 Utilice igbinary-serialize si no te importa un poco sobrecarga. O intarray (por la misma persona) si no te importa usar un paquete ligeramente experimental que puede tener problemas para compartir datos entre arquitecturas ordenadas byte / bit diferentes. No creo que sería demasiado difícil empujar una función de serializar y unserialize función allí si arrancar el código de igbinary para el almacenamiento de arrays numéricos con la endianess correcto. Mirando igbinaryserialize32 e igbinaryunserialize32 en igbinary. c debería ser muy fácil copiar esa funcionalidad a intarray. c. Quita el ltlt0 sin embargo, thats apenas estúpido: P

No comments:

Post a Comment