utf8 español codificacion charset acentos php encoding utf-8

español - utf8 php mysql



¿Cómo manejar la entrada del usuario de caracteres UTF-8 no válidos? (9)

¿Qué hay de despojar a todos los caracteres fuera de su subconjunto dado. Al menos en algunas partes de mi aplicación, no permitiría el uso de caracteres fuera de [aZ] [0-9 conjuntos], por ejemplo, nombres de usuario. Puede crear una función de filtro que elimine silenciosamente todos los caracteres fuera de este rango, o que devuelva un error si los detecta y envía la decisión al usuario.

Estoy buscando una estrategia / consejo general sobre cómo manejar la entrada UTF-8 no válida de los usuarios.

Aunque mi aplicación web usa UTF-8, de alguna manera algunos usuarios ingresan caracteres no válidos. Esto causa errores en json_encode() de PHP json_encode() y en general parece una mala idea para tener alrededor.

Preguntas frecuentes sobre W3C I18N: Formularios multilingües dice "Si se reciben datos que no son UTF-8, se debe enviar un mensaje de error nuevamente".

  • ¿Cómo exactamente esto debería hacerse en un sitio con docenas de lugares diferentes donde se pueden ingresar datos?
  • ¿Cómo se presenta el error de una manera útil para el usuario?
  • ¿Cómo almacena y muestra temporalmente datos de formularios incorrectos para que el usuario no pierda todo su texto? ¿Despojar a los malos personajes? Use un personaje de reemplazo, y ¿cómo?
  • Para los datos existentes en la base de datos, cuando se detectan datos UTF-8 no válidos, ¿debo tratar de convertirlos y guardarlos (cómo? utf8_encode ()? mb_convert_encoding() ?), O dejarlos como están en la base de datos pero haciendo algo (¿qué?) antes de json_encode ()?

EDITAR: Estoy muy familiarizado con la extensión mbstring y no estoy preguntando "cómo funciona UTF-8 en PHP". Me gustaría recibir consejos de personas con experiencia en situaciones del mundo real sobre cómo manejaron esto.

EDIT2: Como parte de la solución, me gustaría ver un método rápido para convertir caracteres no válidos a U + FFFD


Establezca UTF-8 como el conjunto de caracteres para todos los encabezados generados por su código PHP

En cada encabezado de salida de PHP, especifique UTF-8 como la codificación:

header(''Content-Type: text/html; charset=utf-8'');



Intenta hacer lo que Rails hace para obligar a todos los navegadores a publicar siempre datos UTF-8:

<form accept-charset="UTF-8" action="#{action}" method="post"><div style="margin:0;padding:0;display:inline"> <input name="utf8" type="hidden" value="&#x2713;" /> </div> <!-- form fields --> </form>

Consulte railssnowman.info o el parche inicial para obtener una explicación.

  1. Para que el navegador envíe datos de envío de formularios en la codificación UTF-8, solo renderice la página con un encabezado Content-Type de "text / html; charset = utf-8" (o use una etiqueta meta http-equiv ).
  2. Para que el navegador envíe datos de envío de formularios en la codificación UTF-8, incluso si el usuario juega con la codificación de la página (los navegadores permiten que los usuarios lo hagan), use accept-charset="UTF-8" en el formulario.
  3. Hacer que el navegador envíe datos de envío de formularios en la codificación UTF-8, incluso si el usuario juega con la codificación de la página (los navegadores permiten que los usuarios lo hagan), e incluso si el navegador es IE y el usuario cambió la codificación de la página a coreano y ingresó caracteres coreanos en los campos del formulario, agrega una entrada oculta al formulario con un valor como &#x2713; que solo puede ser del juego de caracteres Unicode (y, en este ejemplo, no el juego de caracteres coreano).

La recepción de caracteres no válidos desde su aplicación web podría tener que ver con los conjuntos de caracteres asumidos para los formularios HTML. Puede especificar qué conjunto de caracteres usar para los formularios con el atributo accept-charset :

<form action="..." accept-charset="UTF-8">

También es posible que desee ver preguntas similares en para los punteros sobre cómo manejar los caracteres no válidos, por ejemplo, los de la columna de la derecha, pero creo que es mejor señalar un error al usuario que tratar de limpiar los no válidos. caracteres que causan pérdida inesperada de datos significativos o cambios inesperados de las entradas de su usuario.


Para completar esta pregunta (no necesariamente la mejor respuesta) ...

function as_utf8($s) { return mb_convert_encoding($s, "UTF-8", mb_detect_encoding($s)); }


Puse una clase bastante simple para verificar si la entrada está en UTF-8 y para ejecutar utf8_encode() según sea necesario:

class utf8 { /** * @param array $data * @param int $options * @return array */ public static function encode(array $data) { foreach ($data as $key=>$val) { if (is_array($val)) { $data[$key] = self::encode($val, $options); } else { if (false === self::check($val)) { $data[$key] = utf8_encode($val); } } } return $data; } /** * Regular expression to test a string is UTF8 encoded * * RFC3629 * * @param string $string The string to be tested * @return bool * * @link http://www.w3.org/International/questions/qa-forms-utf-8.en.php */ public static function check($string) { return preg_match(''%^(?: [/x09/x0A/x0D/x20-/x7E] # ASCII | [/xC2-/xDF][/x80-/xBF] # non-overlong 2-byte | /xE0[/xA0-/xBF][/x80-/xBF] # excluding overlongs | [/xE1-/xEC/xEE/xEF][/x80-/xBF]{2} # straight 3-byte | /xED[/x80-/x9F][/x80-/xBF] # excluding surrogates | /xF0[/x90-/xBF][/x80-/xBF]{2} # planes 1-3 | [/xF1-/xF3][/x80-/xBF]{3} # planes 4-15 | /xF4[/x80-/x8F][/x80-/xBF]{2} # plane 16 )*$%xs'', $string); } } // For example $data = utf8::encode($_POST);


Recomiendo simplemente no permitir que la basura entre. No confíe en funciones personalizadas, que pueden atascar su sistema. Simplemente recorra los datos enviados con un alfabeto que diseñe. Cree una cadena de alfabeto aceptable y recorra los datos enviados, byte a byte, como si fuera una matriz. Empuje los caracteres aceptables a una nueva cadena y omita los caracteres inaceptables. Los datos que almacena en su base de datos son datos activados por el usuario, pero no datos proporcionados por el usuario.

EDIT # 4: Reemplazando el caracter malo con entiy:

EDIT # 3: Actualizado: 22 de septiembre de 2010 @ 1:32 pm Motivo: Ahora la cadena devuelta es UTF-8, además utilicé el archivo de prueba que proporcionó como prueba.

<?php // build alphabet // optionally you can remove characters from this array $alpha[]= chr(0); // null $alpha[]= chr(9); // tab $alpha[]= chr(10); // new line $alpha[]= chr(11); // tab $alpha[]= chr(13); // carriage return for ($i = 32; $i <= 126; $i++) { $alpha[]= chr($i); } /* remove comment to check ascii ordinals */ // /* // foreach ($alpha as $key=>$val){ // print ord($val); // print ''<br/>''; // } // print ''<hr/>''; //*/ // // //test case #1 // // $str = ''afsjdfhasjhdgljhasdlfy42we875y342q8957y2wkjrgSAHKDJgfcv kzXnxbnSXbcv ''.chr(160).chr(127).chr(126); // // $string = teststr($alpha,$str); // print $string; // print ''<hr/>''; // // //test case #2 // // $str = ''''.''©?™???''; // $string = teststr($alpha,$str); // print $string; // print ''<hr/>''; // // $str = ''©''; // $string = teststr($alpha,$str); // print $string; // print ''<hr/>''; $file = ''http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt''; $testfile = implode(chr(10),file($file)); $string = teststr($alpha,$testfile); print $string; print ''<hr/>''; function teststr(&$alpha, &$str){ $strlen = strlen($str); $newstr = chr(0); //null $x = 0; if($strlen >= 2){ for ($i = 0; $i < $strlen; $i++) { $x++; if(in_array($str[$i],$alpha)){ // passed $newstr .= $str[$i]; }else{ // failed print ''Found out of scope character. (ASCII: ''.ord($str[$i]).'')''; print ''<br/>''; $newstr .= ''&#65533;''; } } }elseif($strlen <= 0){ // failed to qualify for test print ''Non-existent.''; }elseif($strlen === 1){ $x++; if(in_array($str,$alpha)){ // passed $newstr = $str; }else{ // failed print ''Total character failed to qualify.''; $newstr = ''&#65533;''; } }else{ print ''Non-existent (scope).''; } if(mb_detect_encoding($newstr, "UTF-8") == "UTF-8"){ // skip }else{ $newstr = utf8_encode($newstr); } // test encoding: if(mb_detect_encoding($newstr, "UTF-8")=="UTF-8"){ print ''UTF-8 :D<br/>''; }else{ print ''ENCODED: ''.mb_detect_encoding($newstr, "UTF-8").''<br/>''; } return $newstr.'' (scope: ''.$x.'', ''.$strlen.'')''; }


El atributo accept-charset="UTF-8" es solo una guía que los navegadores deben seguir, no están obligados a enviar eso de esa manera, los bots de envío de formularios son un buen ejemplo ...

Lo que suelo hacer es ignorar los caracteres incorrectos, ya sea a través de iconv() o con las utf8_encode() menos confiables utf8_encode() / utf8_decode() , si usas iconv también tienes la opción de transcribir los caracteres incorrectos.

Aquí hay un ejemplo usando iconv() :

$str_ignore = iconv(''UTF-8'', ''UTF-8//IGNORE'', $str); $str_translit = iconv(''UTF-8'', ''UTF-8//TRANSLIT'', $str);

Si desea mostrar un mensaje de error a sus usuarios, probablemente haga esto de forma global en lugar de por cada valor recibido, algo como esto probablemente funcionaría bien:

function utf8_clean($str) { return iconv(''UTF-8'', ''UTF-8//IGNORE'', $str); } $clean_GET = array_map(''utf8_clean'', $_GET); if (serialize($_GET) != serialize($clean_GET)) { $_GET = $clean_GET; $error_msg = ''Your data is not valid UTF-8 and has been stripped.''; } // $_GET is clean!

También puede querer normalizar nuevas líneas y eliminar caracteres de control (no) visibles, como este:

function Clean($string, $control = true) { $string = iconv(''UTF-8'', ''UTF-8//IGNORE'', $string); if ($control === true) { return preg_replace(''~/p{C}+~u'', '''', $string); } return preg_replace(array(''~/r/n?~'', ''~[^/P{C}/t/n]+~u''), array("/n", ''''), $string); }

Código para convertir de UTF-8 a puntos de código Unicode:

function Codepoint($char) { $result = null; $codepoint = unpack(''N'', iconv(''UTF-8'', ''UCS-4BE'', $char)); if (is_array($codepoint) && array_key_exists(1, $codepoint)) { $result = sprintf(''U+%04X'', $codepoint[1]); } return $result; } echo Codepoint(''à''); // U+00E0 echo Codepoint(''ひ''); // U+3072

Probablemente más rápido que cualquier otra alternativa, sin embargo, no lo han probado extensamente.

Ejemplo:

$string = ''hello world�''; // U+FFFEhello worldU+FFFD echo preg_replace_callback(''/[/p{So}/p{Cf}/p{Co}/p{Cs}/p{Cn}]/u'', ''Bad_Codepoint'', $string); function Bad_Codepoint($string) { $result = array(); foreach ((array) $string as $char) { $codepoint = unpack(''N'', iconv(''UTF-8'', ''UCS-4BE'', $char)); if (is_array($codepoint) && array_key_exists(1, $codepoint)) { $result[] = sprintf(''U+%04X'', $codepoint[1]); } } return implode('''', $result); }

Esto es lo que estabas buscando?