php

Una contribución a Mp3Info: solucionar error que remueve el último carácter

Introducción

Esta mañana justamente estaba planeando un tutorial sobre cómo extraer la información de una canción MP3 que usa el formato Id3 o algo así. Para ello estaba usando la magnífica librería llamada Mp3Info y el lenguaje de programación PHP.

Todo iba bien, hasta que noté algo extraño. Extraje la información de una canción pero regresaba los datos con un carácter de menos. Por ejemplo, si el artista era León Larregui, mostraba León Larregu. O si el nombre de la canción era Locos, mostraba Loco.

Aquí una imagen que lo comprueba:

Información incorrecta, último carácter perdido

Entonces me puse a depurar y depurar por un montón de tiempo hasta que di con la solución que justo ahora vengo a exponer

Resumen nivel 5

Bueno, al final sólo fue agregar el carácter NUL al final de la cadena.

Hice un fork del repositorio aquí, el cual soluciona este bug citado en el repositorio original.

Solución a bug de Mp3info

Arreglar bug de Mp3Info que remueve el último carácter

Probé de todo, primero imprimí la cadena y la analicé. Vi que decía algo como “V o l u m a”, así con espacios. Supuse que es porque usa dos bytes para representar los caracteres unicode o esas cosas, pero tenían un espacio porque el segundo carácter no era usado, ya que todo cabía en un byte.

Luego intenté decodificar la cadena con todos los formatos que devolviera mb_list_encodings usando mb_convert_encoding, pero todo salía feo; con caracteres raros, signos de interrogación y esas cosas.

Más tarde recorrí la cadena y fui imprimiendo su representación ASCII usando la función ord con este código, (no está muy bonito pero estaba depurando, no programando):

<?php
echo "Vamos con '" . $data["information"] . "'\n";
$l = strlen($data["information"]);
for($x = 0; $x < $l; $x++){
    echo ord($data["information"][$x]) . "\n";
}

Comenzaba mostrando el 255 y 254, supongo que son unos bytes que indican otra cosa que desconozco (tal vez algo como un encabezado).

Lo que realmente importaba era que después imprimía el 86 y más tarde el 0; el 86 representaba la V de Voluma. ¿Y ese cero? Así que (y me vengo a dar cuenta de la posible explicación al escribir este post) usaba dos caracteres para representar una letra, por cosas del unicode como lo mencioné anteriormente.

Dejaba ese carácter nulo porque no lo necesitaba, ya que la V se puede representar con un byte. La salida era así:

Depurando con ord

Y fue ahí cuando me di cuenta de que faltaba un cero al final, ya que cada letra llevaba su representación y un 0, o el carácter nulo si hablamos del código ASCII.

Yo creo que PHP, al convertir la codificación, detectaba el 97 como un carácter que estorbaba, porque no usaba 2 bytes, sólo uno; era el sobrante que no tenía pareja.

Así que lo que hice fue agregar al final de la cadena el carácter nulo:

$data["information"] .= chr(0);

La función chr complementa a ord, dado un número devuelve su representación ASCII. Y entonces la salida ahora era distinta:

Agregar NUL al final

Después del 97 ahora sí salía un cero. Si borraba todo mi código de depuración y dejaba todo limpio, la función ahora se veía así:

<?php
private function handleTextFrame($frameSize, $raw)
{
    $data = unpack('C1encoding/A' . ($frameSize - 1) . 'information', $raw);
 
    if ($data['encoding'] == 0x00) # ISO-8859-1
        return mb_convert_encoding($data['information'], 'utf-8', 'iso-8859-1');
    else{ # utf-16
        # Fix the missing last char of the info bug
        # Add NUL character at the end of the string. 
        # Don't ask, just enjoy. Idk why it works, but it works!
        $data["information"] .=  chr(0);
        return mb_convert_encoding($data['information'], 'utf-8', 'utf-16');
    }
}

Simplemente agregué una concatenación. Se ve simple, pero llevó horas escribir esa maldita línea. Y si probaba…

Bug arreglado

Ahora ya devolvía toda la información. Me pregunto qué pasa si el último carácter de la cadena es multibyte, supongo que habría que comprobar si su último byte es NUL y si no entonces concatenar.

El punto es que quedó arreglado y ahora sí continuaré escribiendo el tutorial.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

  • Muy buenas parzibyte,
    Te estoy escribiendo porque estoy interesado en esta librería para implementarla en mi sitio web, te cuento que estoy haciendo un script web el cual contendrá una lista de reproducción de mp3 y hasta ahora puedo extraer todos los datos excepto uno. me refiero a la imagen de portada que trae el Mp3 el cual aparece en los reproductores cuando se esta reproduciendo el archivo de audio.

    llevo varios días buscando información sobre esto pero no encuentro nada que me solucione mi busqueda.

    Me gustaría saber si con esta librería sería capaz de extraer esa imagen de portada que lleva cada mp3.

    Un cordial saludo y espero me puedas responder, si puedes por un correo directo gracias.

    Att: Jose Peguero

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

17 horas hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

1 semana hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

1 semana hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

1 semana hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

1 semana hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

1 semana hace

Esta web usa cookies.