sirve recibir que para funciona ejemplo _request _post _get php regex postback

recibir - Obtenga PHP para dejar de reemplazar ''.'' caracteres en arrays $_GET o $_POST?



recibir variables get php (14)

..

¿Por qué no simplemente conviertes todos los puntos en algún tipo de token, como por ejemplo, en (~ # ~) y luego lo publicas? Al recibir los vars, puedes reconvertirlos. Esto es porque a veces NECESITAMOS publicar subrayados ... y los perderíamos si reconvertimos todos los "_" a "." S ...

Si paso las variables PHP con . en sus nombres vía $ _GET PHP los reemplaza automáticamente con _ caracteres. Por ejemplo:

<?php echo "url is ".$_SERVER[''REQUEST_URI'']."<p>"; echo "x.y is ".$_GET[''x.y''].".<p>"; echo "x_y is ".$_GET[''x_y''].".<p>";

... muestra lo siguiente:

url is /SpShipTool/php/testGetUrl.php?x.y=a.b x.y is . x_y is a.b.

... mi pregunta es esta: ¿hay alguna manera de que pueda detener esto? No puedo por mi vida descubrir lo que he hecho para merecer esto

La versión de PHP con la que me estoy ejecutando es 5.2.4-2ubuntu5.3.


Aquí está la explicación de PHP.net de por qué lo hace:

Puntos en nombres de variables entrantes

Normalmente, PHP no altera los nombres de las variables cuando se pasan a un script. Sin embargo, debe tenerse en cuenta que el punto (punto, punto y coma) no es un carácter válido en un nombre de variable PHP. Por la razón, míralo:

<?php $varname.ext; /* invalid variable name */ ?>

Ahora, lo que el analizador ve es una variable llamada $ varname, seguida por el operador de concatenación de cadenas, seguido de la cadena de barras (es decir, una cadena sin comillas que no coincide con ninguna tecla conocida o palabras reservadas) ''ext''. Obviamente, esto no tiene el resultado esperado.

Por esta razón, es importante tener en cuenta que PHP reemplazará automáticamente cualquier punto en los nombres de variables entrantes con guiones bajos.

Eso es de http://ca.php.net/variables.external .

Además, según este comentario, estos otros personajes se convierten en guiones bajos:

La lista completa de caracteres de nombre de campo que PHP convierte a _ (guión bajo) es la siguiente (no solo punto):

  • chr (32) () (espacio)
  • chr (46) (.) (punto)
  • chr (91) ([) (abrir el corchete cuadrado)
  • chr (128) - chr (159) (varios)

Así que parece que estás atrapado con eso, así que tendrás que convertir los guiones bajos a puntos en tu guión usando la sugerencia de dawnerd (yo solo usaría str_replace ).


Bueno, la función que incluyo a continuación, "getRealPostArray ()", no es una solución bonita, pero maneja matrices y admite ambos nombres: "alpha_beta" y "alpha.beta":

<input type=''text'' value=''First-.'' name=''alpha.beta[a.b][]'' /><br> <input type=''text'' value=''Second-.'' name=''alpha.beta[a.b][]'' /><br> <input type=''text'' value=''First-_'' name=''alpha_beta[a.b][]'' /><br> <input type=''text'' value=''Second-_'' name=''alpha_beta[a.b][]'' /><br>

mientras que var_dump ($ _ POST) produce:

''alpha_beta'' => array (size=1) ''a.b'' => array (size=4) 0 => string ''First-.'' (length=7) 1 => string ''Second-.'' (length=8) 2 => string ''First-_'' (length=7) 3 => string ''Second-_'' (length=8)

var_dump (getRealPostArray ()) produce:

''alpha.beta'' => array (size=1) ''a.b'' => array (size=2) 0 => string ''First-.'' (length=7) 1 => string ''Second-.'' (length=8) ''alpha_beta'' => array (size=1) ''a.b'' => array (size=2) 0 => string ''First-_'' (length=7) 1 => string ''Second-_'' (length=8)

La función, por lo que vale:

function getRealPostArray() { if ($_SERVER[''REQUEST_METHOD''] !== ''POST'') {#Nothing to do return null; } $neverANamePart = ''~#~''; #Any arbitrary string never expected in a ''name'' $postdata = file_get_contents("php://input"); $post = []; $rebuiltpairs = []; $postraws = explode(''&'', $postdata); foreach ($postraws as $postraw) { #Each is a string like: ''xxxx=yyyy'' $keyvalpair = explode(''='',$postraw); if (empty($keyvalpair[1])) { $keyvalpair[1] = ''''; } $pos = strpos($keyvalpair[0],''%5B''); if ($pos !== false) { $str1 = substr($keyvalpair[0], 0, $pos); $str2 = substr($keyvalpair[0], $pos); $str1 = str_replace(''.'',$neverANamePart,$str1); $keyvalpair[0] = $str1.$str2; } else { $keyvalpair[0] = str_replace(''.'',$neverANamePart,$keyvalpair[0]); } $rebuiltpair = implode(''='',$keyvalpair); $rebuiltpairs[]=$rebuiltpair; } $rebuiltpostdata = implode(''&'',$rebuiltpairs); parse_str($rebuiltpostdata, $post); $fixedpost = []; foreach ($post as $key => $val) { $fixedpost[str_replace($neverANamePart,''.'',$key)] = $val; } return $fixedpost; }


Después de ver la solución de Rok, he encontrado una versión que aborda las limitaciones en mi respuesta a continuación, crb arriba y la solución de Rok también. Vea una versión mejorada .

La respuesta de @crb above es un buen comienzo, pero hay un par de problemas.

  • Reprocesa todo, lo cual es excesivo; solo aquellos campos que tienen un "." en el nombre necesitan ser reprocesados.
  • No maneja las matrices de la misma manera que lo hace el procesamiento PHP nativo, por ejemplo, para claves como "foo.bar []".

La siguiente solución aborda ambos problemas ahora (tenga en cuenta que se ha actualizado desde que se publicó originalmente). Esto es aproximadamente un 50% más rápido que mi respuesta anterior en mis pruebas, pero no manejará situaciones donde los datos tienen la misma clave (o una clave que se extrae igual, por ejemplo, foo.bar y foo_bar se extraen como foo_bar).

<?php public function fix2(&$target, $source, $keep = false) { if (!$source) { return; } preg_match_all( ''/ # Match at start of string or & (?:^|(?<=&)) # Exclude cases where the period is in brackets, e.g. foo[bar.blarg] [^=&/[]* # Affected cases: periods and spaces (?:/.|%20) # Keep matching until assignment, next variable, end of string or # start of an array [^=&/[]* /x'', $source, $matches ); foreach (current($matches) as $key) { $key = urldecode($key); $badKey = preg_replace(''/(/.| )/'', ''_'', $key); if (isset($target[$badKey])) { // Duplicate values may have already unset this $target[$key] = $target[$badKey]; if (!$keep) { unset($target[$badKey]); } } } }


Destacando una respuesta real de Johan en un comentario anterior: envolví mi publicación completa en una matriz de nivel superior que elude por completo el problema sin requerir un gran procesamiento.

En la forma que haces

<input name="data[database.username]"> <input name="data[database.password]"> <input name="data[something.else.really.deep]">

en lugar de

<input name="database.username"> <input name="database.password"> <input name="something.else.really.deep">

y en el controlador de correos, solo desenvuélvelo:

$posdata = $_POST[''data''];

Para mí, esto fue un cambio de dos líneas, ya que mis puntos de vista fueron completamente modelados.

FYI. Estoy usando puntos en mis nombres de campo para editar árboles de datos agrupados.


El funcionamiento de esta función es un truco genial que inventé durante mis vacaciones de verano en 2013. Algún día escribiré una publicación en un blog sobre ella.

Esta solución funciona universalmente y tiene soporte de matriz profunda, por ejemplo aa[x][ba]=10 . Utiliza parse_str() detrás de escena con algunos preprocesamientos.

function fix($source) { $source = preg_replace_callback( ''/(^|(?<=&))[^=[&]+/'', function($key) { return bin2hex(urldecode($key[0])); }, $source ); parse_str($source, $post); $result = array(); foreach ($post as $key => $val) { $result[hex2bin($key)] = $val; } return $result; }

Y luego puede llamar a esta función de esta manera, dependiendo de la fuente:

$_POST = fix(file_get_contents(''php://input'')); $_GET = fix($_SERVER[''QUERY_STRING'']); $_COOKIE = fix($_SERVER[''HTTP_COOKIE'']);

Para PHP por debajo de 5.4: use base64_encode lugar de bin2hex y bin2hex lugar de hex2bin .


Este enfoque es una versión alterada de Rok Kralj, pero con algunos ajustes al trabajo, para mejorar la eficiencia (evita devoluciones de llamadas innecesarias, codificación y decodificación en claves no afectadas) y para manejar correctamente las teclas de matriz.

Se encuentra disponible una esencia con pruebas y cualquier comentario o sugerencia es bienvenido aquí o allá.

public function fix(&$target, $source, $keep = false) { if (!$source) { return; } $keys = array(); $source = preg_replace_callback( ''/ # Match at start of string or & (?:^|(?<=&)) # Exclude cases where the period is in brackets, e.g. foo[bar.blarg] [^=&/[]* # Affected cases: periods and spaces (?:/.|%20) # Keep matching until assignment, next variable, end of string or # start of an array [^=&/[]* /x'', function ($key) use (&$keys) { $keys[] = $key = base64_encode(urldecode($key[0])); return urlencode($key); }, $source ); if (!$keep) { $target = array(); } parse_str($source, $data); foreach ($data as $key => $val) { // Only unprocess encoded keys if (!in_array($key, $keys)) { $target[$key] = $val; continue; } $key = base64_decode($key); $target[$key] = $val; if ($keep) { // Keep a copy in the underscore key version $key = preg_replace(''/(/.| )/'', ''_'', $key); $target[$key] = $val; } } }


Esto sucede porque un período es un carácter no válido en el nombre de una variable, cuya reason radica muy profundamente en la implementación de PHP, por lo que no hay soluciones fáciles (aún).

Mientras tanto, puedes solucionar este problema al:

  1. Accediendo a los datos de consulta sin procesar a través de la php://input para datos POST o $_SERVER[''QUERY_STRING''] para obtener datos GET
  2. Usando una función de conversión.

La función de conversión siguiente (PHP> = 5.4) codifica los nombres de cada par clave-valor en una representación hexadecimal y luego realiza un parse_str() regular; una vez hecho esto, revierte los nombres hexadecimales a su forma original:

function parse_qs($data) { $data = preg_replace_callback(''/(?:^|(?<=&))[^=[]+/'', function($match) { return bin2hex(urldecode($match[0])); }, $data); parse_str($data, $values); return array_combine(array_map(''hex2bin'', array_keys($values)), $values); } // work with the raw query string $data = parse_qs($_SERVER[''QUERY_STRING'']);

O:

// handle posted data (this only works with application/x-www-form-urlencoded) $data = parse_qs(file_get_contents(''php://input''));


La razón por la que esto ocurre es debido a la antigua funcionalidad register_globals de PHP. Los . el carácter no es un carácter válido en un nombre de variable, por lo que PHP lo convierte en un guión bajo para asegurarse de que haya compatibilidad.

En resumen, no es una buena práctica hacer períodos en variables de URL.


Mi solución a este problema fue rápida y sucia, pero todavía me gusta. Simplemente quería publicar una lista de nombres de archivos que se marcaron en el formulario. Utilicé base64_encode para codificar los nombres de archivo dentro del marcado y luego lo decodifiqué con base64_decode antes de usarlos.


Mi solución actual (basada en respuestas de temas previos):

function parseQueryString($data) { $data = rawurldecode($data); $pattern = ''/(?:^|(?<=&))[^=&/[]*[^=&/[]*/''; $data = preg_replace_callback($pattern, function ($match){ return bin2hex(urldecode($match[0])); }, $data); parse_str($data, $values); return array_combine(array_map(''hex2bin'', array_keys($values)), $values); } $_GET = parseQueryString($_SERVER[''QUERY_STRING'']);


Pregunta contestada desde hace mucho tiempo, pero en realidad hay una mejor respuesta (o solución alternativa). PHP te permite el flujo de entrada sin procesar , por lo que puedes hacer algo como esto:

$query_string = file_get_contents(''php://input'');

que le dará la matriz $ _POST en el formato de cadena de consulta, los períodos como deberían ser.

Luego puede analizarlo si lo necesita (según el comentario de POSTER )

<?php // Function to fix up PHP''s messing up input containing dots, etc. // `$source` can be either ''POST'' or ''GET'' function getRealInput($source) { $pairs = explode("&", $source == ''POST'' ? file_get_contents("php://input") : $_SERVER[''QUERY_STRING'']); $vars = array(); foreach ($pairs as $pair) { $nv = explode("=", $pair); $name = urldecode($nv[0]); $value = urldecode($nv[1]); $vars[$name] = $value; } return $vars; } // Wrapper functions specifically for GET and POST: function getRealGET() { return getRealInput(''GET''); } function getRealPOST() { return getRealInput(''POST''); } ?>

Muy útil para los parámetros de OpenID, que contienen ambos ''.'' y ''_'', cada uno con un cierto significado!


Si busca alguna forma de obtener literalmente PHP, deje de reemplazar ''.'' caracteres en matrices $ _GET o $ _POST; luego, una de ellas es modificar el origen de PHP (y en este caso es relativamente sencillo).

ADVERTENCIA: ¡modificar la fuente de PHP C es una opción avanzada!

También vea este informe de error PHP que sugiere la misma modificación.

Para explorar, necesitarás:

  • descarga el código fuente C de PHP
  • desactivar el . cheque de reemplazo
  • ./configure , crea y despliega tu versión personalizada de PHP

El cambio de fuente en sí es trivial e implica la actualización de solo la mitad de una línea en main/php_variables.c :

.... /* ensure that we don''t have spaces or dots in the variable name (not binary safe) */ for (p = var; *p; p++) { if (*p == '' '' /*|| *p == ''.''*/) { *p=''_''; ....

Nota: en comparación con el original || *p == ''.'' || *p == ''.'' ha sido comentado

Ejemplo de salida:

dado un QUERY_STRING de aa[]=bb&a.a[]=BB&c%20c=dd , ejecutando <?php print_r($_GET); ahora produce:

Array ( [a.a] => Array ( [0] => bb [1] => BB ) [c_c] => dd )

Notas:

  • este parche solo aborda la pregunta original (detiene el reemplazo de puntos, no de espacios).
  • ejecutar este parche será más rápido que las soluciones de nivel de script, pero esas respuestas pure-.php son aún preferibles (porque evitan cambiar el PHP).
  • en teoría, es posible un enfoque de polifiltrado y podría combinar enfoques: prueba para el cambio de nivel C utilizando parse_str() y (si no está disponible) recurrir a métodos más lentos.

Usando crb''s, quería volver a crear la matriz $_POST en su conjunto, pero tenga en cuenta que aún deberá asegurarse de que está codificando y decodificando correctamente tanto en el cliente como en el servidor. Es importante entender cuándo un personaje es verdaderamente inválido y es verdaderamente válido . Además, las personas deben seguir escapando de los datos del cliente y usarlos antes de usarlo con cualquier comando de base de datos sin excepción .

<?php unset($_POST); $_POST = array(); $p0 = explode(''&'',file_get_contents(''php://input'')); foreach ($p0 as $key => $value) { $p1 = explode(''='',$value); $_POST[$p1[0]] = $p1[1]; //OR... //$_POST[urldecode($p1[0])] = urldecode($p1[1]); } print_r($_POST); ?>

Recomiendo usar esto solo para casos individuales, de manera improvisada. No estoy seguro de los puntos negativos de poner esto en la parte superior de su archivo de encabezado principal.