¿Cómo representa PHP internamente las cadenas?

18

UTF8?
UTF16?

¿Las cadenas en PHP también hacen un seguimiento de la codificación utilizada?

Veamos este script por ejemplo. Digamos que corro:

$original = "शक्नोम्यत्तुम्";

¿Qué pasa realmente?

Obviamente, creo $originalque no contendrá solo 7 caracteres. Esos glifos deben estar representados por varios bytes allí.

Entonces lo hago:

$converted = mb_convert_encoding ($original , "UTF-8");

¿Qué va a pasar $converted? ¿Cómo será $converteddiferente de $original?

¿Será exactamente la misma secuencia de bytes $originalpero con una codificación diferente?

user4951
fuente
1
¿Qué versión de PHP? PHP <6 no puede manejar UTF-8 nativo. Sin embargo, hay paquetes y métodos que ayudan / resuelven este problema. Google diversión con utf-8 y php. Luego cambie a otra plataforma en lugar de PHP. :)
Andrew T Finnell
44
PHP <6? Eso incluiría todas las versiones de PHP lanzado nunca ...
tdammers
1
Además, PHP puede manejar UTF-8, simplemente no tiene un tipo de datos dedicado, por lo que debe mirar lo que está haciendo.
tdammers

Respuestas:

22

Una cadena PHP es solo una secuencia de bytes, sin codificación alguna. Los valores de cadena pueden provenir de varias fuentes: el cliente (a través de HTTP), una base de datos, un archivo o literales de cadena en su código fuente. PHP lee todo esto como secuencias de bytes, y nunca extrae ninguna información de codificación.

Siempre que todas sus fuentes de datos y destinos usen la misma codificación, lo peor que puede suceder es que las posiciones de las cadenas sean incorrectas (si usa codificaciones de varios bytes), ya que PHP contará bytes, no caracteres.

Pero si las codificaciones no coinciden (por ejemplo, escribe un literal de cadena en un archivo fuente almacenado como UTF-8 y luego lo envía a una base de datos que espera Latin-1), PHP no realizará ninguna conversión por usted: lo hará felizmente copie los bytes en bruto.

La solución más sensata es esta:

  • Establezca la codificación interna de PHP en UTF-8.
  • Guarde todos sus archivos de origen como UTF-8.
  • Use UTF-8 como codificación de salida (no olvide enviar Content-typeencabezados adecuados ).
  • Configure la conexión de la base de datos para usar UTF-8 ( SET NAMES UTF8en MySQL).
  • Configure todo lo demás para que sea UTF-8 si es posible.
  • Para cualquier cosa que no pueda controlar (por ejemplo, servicios web de terceros), asegúrese de conocer la codificación, y convertir a UTF-8 lo antes posible, y volver a la otra codificación lo más tarde posible.

¿Por qué UTF-8? Debido a que puede representar todos los caracteres Unicode y, por lo tanto, reemplaza todas las codificaciones existentes de 7 y 8 bits, y debido a que es binariamente compatible con ASCII, es decir, cada cadena ASCII válida también es una cadena UTF-8 válida (pero no vv .).

En su ejemplo, lo que sucede es esto.

Primero, guarde su archivo fuente; su editor de texto probablemente esté configurado para usar UTF-8, por lo que su literal de cadena termina codificado en UTF-8 en el disco. PHP lee este archivo, interpretando la cadena como una serie de bytes; $originalahora contiene una cadena codificada UTF-8 de 7 caracteres, que es solo una secuencia de bytes (aunque contiene más de 7 bytes, porque cada carácter está representado por dos o más bytes). Si luego llama echo $original, la cadena codificada se envía al cliente tal cual; Si le ha dicho al cliente que espere UTF-8, todo está bien, pero si no lo ha hecho, PHP no tiene forma de notar la diferencia, y terminará con basura en el navegador. Como experimento, prueba esto:

$original = "शक्नोम्यत्तुम्";
echo strlen($original);

strlen es independiente de la codificación y asume una codificación de 8 bits de ancho fijo, es decir, un byte por carácter, por lo que contará bytes, no caracteres.

tdammers
fuente
Entonces $ convert representará la misma cadena pero en otra codificación. La codificación en bruto real, que es lo que almacena PhP, será diferente.
user4951
2
Lo repetiré para usted: PHP almacena bytes, no caracteres, y no sabe nada sobre codificaciones (aunque algunas funciones de la biblioteca sí.)
tdammers
1
Ah, y es "PHP", no "PhP".
tdammers
2
si los bytes sin procesar son los mismos, ¿cuál es la diferencia entre $ original y $ convertido? Eso es lo que estoy preguntando.
user4951
2
Oh, está bien, a eso te refieres. Sí, los bytes sin formato cambian según la conversión de codificación. Sin embargo, PHP no recuerda la codificación, por lo que si convierte una cadena de, digamos, utf-8 a latin-1, y luego trata el resultado como utf-8, verá resultados extraños.
tdammers