rawurlencode - urlencode php
¿PHP unserialize falla con caracteres no codificados? (13)
$ser = ''a:2:{i:0;s:5:"héllö";i:1;s:5:"wörld";}''; // fails
$ser2 = ''a:2:{i:0;s:5:"hello";i:1;s:5:"world";}''; // works
$out = unserialize($ser);
$out2 = unserialize($ser2);
print_r($out);
print_r($out2);
echo "<hr>";
¿Pero por qué?
¿Debo codificar antes de serializar que? ¿Cómo?
Estoy usando Javascript para escribir la cadena serializada en un campo oculto, que $ _POST de PHP
En JS tengo algo así como:
function writeImgData() {
var caption_arr = new Array();
$(''.album img'').each(function(index) {
caption_arr.push($(this).attr(''alt''));
});
$("#hidden-field").attr("value", serializeArray(caption_arr));
};
El problema es, como lo señala Alix , relacionado con la codificación.
Hasta PHP 5.4 la codificación interna para PHP era ISO-8859-1, esta codificación usa un solo byte para algunos caracteres que en unicode son multibyte. El resultado es que los valores multibyte serializados en el sistema UTF-8 no serán legibles en los sistemas ISO-8859-1.
Para evitar problemas como este, asegúrese de que todos los sistemas usen la misma codificación:
mb_internal_encoding(''utf-8'');
$arr = array(''foo'' => ''bár'');
$buf = serialize($arr);
Puede usar utf8_(encode|decode)
para limpiar:
// Set system encoding to iso-8859-1
mb_internal_encoding(''iso-8859-1'');
$arr = unserialize(utf8_encode($serialized));
print_r($arr);
En mi caso, el problema era con los finales de línea (es probable que algún editor haya cambiado mi archivo de DOS a Unix).
Puse estas envolturas apadtive:
function unserialize_fetchError($original, &$unserialized, &$errorMsg) {
$unserialized = @unserialize($original);
$errorMsg = error_get_last()[''message''];
return ( $unserialized !== false || $original == ''b:0;'' ); // "$original == serialize(false)" is a good serialization even if deserialization actually returns false
}
function unserialize_checkAllLineEndings($original, &$unserialized, &$errorMsg, &$lineEndings) {
if ( unserialize_fetchError($original, $unserialized, $errorMsg) ) {
$lineEndings = ''unchanged'';
return true;
} elseif ( unserialize_fetchError(str_replace("/n", "/n/r", $original), $unserialized, $errorMsg) ) {
$lineEndings = ''/n to /n/r'';
return true;
} elseif ( unserialize_fetchError(str_replace("/n/r", "/n", $original), $unserialized, $errorMsg) ) {
$lineEndings = ''/n/r to /n'';
return true;
} elseif ( unserialize_fetchError(str_replace("/r/n", "/n", $original), $unserialized, $errorMsg) ) {
$lineEndings = ''/r/n to /n'';
return true;
} //else
return false;
}
En respuesta a @Lionel anterior, de hecho, la función mb_unserialize () tal como la propusiste no funcionará si la secuencia serializada contiene una secuencia de caracteres ";
(comillas seguidas de punto y coma). Utilícela con precaución. Por ejemplo:
$test = ''test";string'';
// $test is now ''s:12:"test";string";''
$string = preg_replace(''!s:(/d+):"(.*?)";!se'', "''s:''.strlen(''$2'').'':/"$2/";''", $test);
print $string;
// output: s:4:"test";string"; (Wrong!!)
JSON es la forma de ir, como lo mencionaron otros, en mi humilde opinión
Nota: Publico esto como una nueva respuesta ya que no sé cómo responder directamente (nuevo aquí).
La razón por la cual unserialize()
falla con:
$ser = ''a:2:{i:0;s:5:"héllö";i:1;s:5:"wörld";}'';
Es porque la longitud para héllö
y wörld
es incorrecta, ya que PHP no maneja correctamente las cadenas de bytes múltiples de forma nativa:
echo strlen(''héllö''); // 7
echo strlen(''wörld''); // 6
Sin embargo, si intentas unserialize()
la siguiente cadena correcta:
$ser = ''a:2:{i:0;s:7:"héllö";i:1;s:6:"wörld";}'';
echo ''<pre>'';
print_r(unserialize($ser));
echo ''</pre>'';
Funciona:
Array
(
[0] => héllö
[1] => wörld
)
Si usa PHP serialize()
, debe calcular correctamente las longitudes de los índices de cadenas de varios bytes.
Por otro lado, si desea trabajar con datos serializados en múltiples idiomas (de programación), debe olvidarlo y pasar a algo como JSON, que es mucho más estandarizado.
Le aconsejo que use javascript para codificar como json y luego use json_decode para deserializar.
No use la serialización / desserialización de PHP cuando el otro extremo no sea PHP. No está destinado a ser un formato portátil; por ejemplo, incluso incluye caracteres ascii-1 para claves protegidas, que no es nada que quieras tratar en javascript (aunque funcionaría perfectamente bien, es extremadamente feo).
En su lugar, use un formato portátil como JSON . XML también haría el trabajo, pero JSON tiene menos sobrecarga y es más amigable con los programadores ya que puedes analizarlo fácilmente en una estructura de datos simple en lugar de tener que lidiar con árboles XPath, DOM, etc.
Publicar por fascículos:
foreach ($income_data as $key => &$value)
{
$value = urlencode($value);
}
$data_str = serialize($income_data);
Deserializar:
$data = unserialize($data_str);
foreach ($data as $key => &$value)
{
$value = urldecode($value);
}
Respuesta de modificada para trabajar con PHP> = 5.5:
function mb_unserialize($string) {
$string2 = preg_replace_callback(
''!s:(/d+):"(.*?)";!s'',
function($m){
$len = strlen($m[2]);
$result = "s:$len:/"{$m[2]}/";";
return $result;
},
$string);
return unserialize($string2);
}
Este código usa preg_replace_callback como preg_replace con el modificador / e obsoleto desde PHP 5.5.
Sé que esto fue publicado hace un año, pero tengo este problema y me encuentro con esto, y de hecho encontré una solución para ello. ¡Este pedazo de código funciona como el encanto!
La idea detrás es fácil. Simplemente lo está ayudando al recalcular la longitud de las cadenas multibyte según lo publicado por @Alix arriba.
Algunas modificaciones deberían adaptarse a su código:
/**
* Mulit-byte Unserialize
*
* UTF-8 will screw up a serialized string
*
* @access private
* @param string
* @return string
*/
function mb_unserialize($string) {
$string = preg_replace(''!s:(/d+):"(.*?)";!se'', "''s:''.strlen(''$2'').'':/"$2/";''", $string);
return unserialize($string);
}
Fuente: http://snippets.dzone.com/posts/show/6592
¡Probado en mi máquina, y funciona como un encanto!
Una pequeña variación más aquí que con suerte ayudará a alguien ... Estaba serializando una matriz y luego escribiéndola en una base de datos. Al recuperar los datos, la operación de deserialización estaba fallando.
Resultó que el campo de texto largo de la base de datos en el que estaba escribiendo usaba latin1 y no UTF8. Cuando lo cambié, todo funcionó como estaba planeado.
¡Gracias a todos los que mencionaron la codificación de caracteres y me pusieron en el camino correcto!
este trabajó para mí
function mb_unserialize($string) {
$string = mb_convert_encoding($string, "UTF-8", mb_detect_encoding($string, "UTF-8, ISO-8859-1, ISO-8859-15", true));
$string = preg_replace_callback(
''/s:([0-9]+):"(.*?)";/'',
function ($match) {
return "s:".strlen($match[2]).":/"".$match[2]."/";";
},
$string
);
return unserialize($string);
}
podemos dividir la cadena en una matriz:
$finalArray = array();
$nodeArr = explode(''&'', $_POST[''formData'']);
foreach($nodeArr as $value){
$childArr = explode(''='', $value);
$finalArray[$childArr[0]] = $childArr[1];
}
/**
* MULIT-BYTE UNSERIALIZE
*
* UTF-8 will screw up a serialized string
*
* @param string
* @return string
*/
function mb_unserialize($string) {
$string = preg_replace_callback(''/!s:(/d+):"(.*?)";!se/'', function($matches) { return ''s:''.strlen($matches[1]).'':"''.$matches[1].''";''; }, $string);
return unserialize($string);
}