web-dev-qa-db-fra.com

PHP des valeurs $ _POST manquantes mais présentes dans php: // input

J'ai un très grand formulaire html (contenant un tableau avec des lignes, qui contiennent plusieurs entrées), que je dois soumettre à un script PHP via la demande POST. Le problème est que certaines valeurs ne passent pas et sont absentes dans $ _POST superglobal.

J'ai vérifié (en utilisant l'extension Firebug) que les valeurs sont réellement envoyées au serveur par le navigateur.

$ _POST est rempli, mais certaines valeurs manquent tout simplement.

J'ai vérifié quelle est la demande brute en utilisant:

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

et la chaîne retournée a les valeurs. Ils ne sont simplement pas analysés dans le tableau $ _POST. La chose étrange que j'ai remarquée est qu'il semble que les valeurs d'entrée php: // sont coupées après une certaine longueur et que le reste de la chaîne ne passe pas à $ _POST.

J'ai pensé à post_max_size et memory_limit et leur ai attribué de grandes valeurs:

memory_limit = 256M
post_max_size = 150M

En raison de la grande taille du formulaire et de la demande, je ne peux pas le poster ici, mais je peux poster un script php avec lequel je déboguais le problème:


var_dump($file = file_get_contents('php://input'));
var_dump($_POST);
//... then i parsed the $file

Version du serveur: Apache/2.2.9 (Debian)
Version PHP: PHP 5.3.2-0.dotdeb.2

Enyone peut-il expliquer la raison d'un tel comportement étrange PHP, et que dois-je faire (modifier les paramètres PHP, le code?) Pour utiliser le tableau $ _POST lors du traitement du formulaire?

EDIT: Pour être clair: non seulement les valeurs sont manquantes. $ _POST ne contient pas ces clés non plus.

ex. fragment de post brut:

t_dodparam%5B198%5D=&t_dodparam2%5B198%5D=&t_kolejnosc%5B198%5D=199&n_indeks=201&n_wartosc=testtesttest

La clé 't_dodparam' est dans le post et elle a la clé 198. Le reste des paramètres est manquant (par exemple, t_dodparam2 est dans le post, mais il n'a pas de clé telle que 198 et il n'y a pas de clé telle que n_wartosc dans $ _POST).

45
jankes

PHP modifie les champs contenant les caractères espace, point, crochet ouvert et autres pour être compatibles avec les register_globals obsolètes

vous pouvez trouver beaucoup de solutions de contournement dans les commentaires ici: PHP: Variables de sources externes

Pour Exampe (commentaire de POSTer):

<?php
//Function to fix up PHP's messing up POST input containing dots, etc.
function getRealPOST() {
    $pairs = explode("&", file_get_contents("php://input"));
    $vars = array();
    foreach ($pairs as $pair) {
        $nv = explode("=", $pair);
        $name = urldecode($nv[0]);
        $value = urldecode($nv[1]);
        $vars[$name] = $value;
    }
    return $vars;
}
?>
29
felixsigl

Je viens de résoudre ce problème en ajoutant une valeur à max_input_vars dans mon fichier de configuration PHP. Selon this . Il a été introduit dans la version 5.3.9. Pourtant, après certaines mises à niveau du paquet, j'ai rencontré le problème en 5.3.2.

La valeur par défaut pour max_input_vars est 1000, ce qui était trop petit pour mon formulaire.

29
Juanita

Cela pourrait être causé par beaucoup de choses différentes. Le mieux est de vérifier votre journal des erreurs. Un grand nombre des causes de ce problème placent des messages dans le journal des erreurs, mais ne les affichent pas dans votre application PHP. 

Certaines des causes possibles:

Suhosin

Suhosin est une extension pour PHP conçue pour protéger les serveurs et les utilisateurs des failles connues et inconnues des PHP applications et du PHP noyau. Une des choses qu'il fait est de limiter la taille de $ _POST, $ _GET, $ _REQUEST et $ _COOKIE. Si votre problème est Suhosin, vous obtiendrez une erreur dans votre journal telle que

ALERT - configuré POST limite de variable dépassée - Variable supprimée 'foo'

La solution est simple, il suffit d’augmenter le nombre maximum de variables autorisées dans le fichier php.ini. Si vous n’avez pas de section suhosin, créez-en une. Comme tels:

[suhosin]
suhosin.request.max_vars = 1000 # Default is 200
suhosin.post.max_vars = 1000 # Default is 200

Cela peut être provoqué par d'autres paramètres de suhosin, mais ce sont les candidats les plus probables.

Noms de champs de formulaire non valides

De retour dans l'ancien temps PHP avait un paramètre appelé register_globals (maintenant supprimé) qui convertissait automatiquement GET et POST variables en PHP variables. Ainsi, si votre formulaire comportait les champs "foo" et "bar", les variables $ foo et $ bar seraient automatiquement créées lors de l'envoi de ce formulaire. Cependant, plusieurs caractères ne sont pas valides pour une utilisation dans PHP noms de variables (espace, point, crochet ouvert, etc.). Selon les caractères que vous avez utilisés, les variables non valides peuvent être supprimées, leur valeur doit être supprimée ou non définies dans la variable. En dépit du fait que register_globals n'est plus utilisé, PHP continue de supprimer ces caractères lors de la construction de $ _POST, $ _GET, $ _REQUEST et $ _COOKIE. Si vous ne parvenez pas à corriger les valeurs des champs de formulaire, essayez l'une des solutions suivantes:

<?php
/**
 * Converts raw POST data into an array.
 * 
 * Does not work for hierarchical POST data.
 *
 * @return array
 */
function real_post() {
  static $post;
  if (!isset($post)) {
    $pairs = explode("&", file_get_contents("php://input"));
    $post = array();
    foreach ($pairs as $pair) {
      $x = explode("=", $pair);
      $post[rawurldecode($x[0])] = rawurldecode($x[1]);
    }
  }
  return $post;
}
?>
10
Dalin

Pourquoi ne pas utiliser "parse_str" pour convertir la chaîne de requête en structures php? Cette fonction est l'inverse de http_build_query.

    $b = array();
    parse_str(file_get_contents("php://input"), $b);
6
xavividal

J'avais le même problème et il s'est avéré que j'utilisais AJAX pour modifier dynamiquement le champ d'entrée en fonction d'autres entrées du formulaire. La fonction ajax a recréé l'entrée et n'a pas pu inclure un nom d'entrée.

1
mosherjm

Je suis tombé sur cet article (certes ancien) tout en essayant de trouver une solution au bogue de la clé d'objet Javascript, y compris les crochets, puis PHP se confondre et agissant comme s'il n'avait jamais entendu parler d'imbrication. @Dalin a une bonne réponse de base, mais il ne crée pas de tableau imbriqué, ni ne convertit les types de valeur en boolean/number - d'où ma version ( get_real_post () est également sur GitHub).

Malgré le nom, cela devrait fonctionner de la même manière pour _GET (c'est-à-dire tout ce que php://input saisit).

/**
 * Gets the _POST data with correct handling of nested brackets:
 * "path[to][data[nested]]=value"
 * "path"
 *    -> "to"
 *       -> "data[nested]" = value
 * @return array
 */
function get_real_post() {

    function set_nested_value(&$arr, &$keys, &$value) {
        $key = array_shift($keys);
        if (count($keys)) {
            // Got deeper to go
            if (!array_key_exists($key, $arr)) {
                // Make sure we can get deeper if we've not hit this key before
                $arr[$key] = array();
            } elseif (!is_array($arr[$key])) {
                // This should never be relevant for well formed input data
                throw new Exception("Setting a value and an array with the same key: $key");
            }
            set_nested_value($arr[$key], $keys, $value);
        } elseif (empty($key)) {
            // Setting an Array
            $arr[] = $value;
        } else {
            // Setting an Object
            $arr[$key] = $value;
        }
    }

    $input = array();
    $parts = array();
    $pairs = explode("&", file_get_contents("php://input"));
    foreach ($pairs as $pair) {
        $key_value = explode("=", $pair, 2);
        preg_match_all("/([a-zA-Z0-9]*)(?:\[([^\[\]]*(?:(?R)[^\[\]]*)*)\])?/", urldecode($key_value[0]), $parts);
        $keys = array($parts[1][0]);
        if (!empty($parts[2][0])) {
            array_pop($parts[2]); // Remove the blank one on the end
            $keys = array_merge($keys, $parts[2]);
        }
        $value = urldecode($key_value[1]);
        if ($value == "true") {
            $value = true;
        } else if ($value == "false") {
            $value = false;
        } else if (is_numeric($value)) {
            if (strpos($value, ".") !== false) {
                $num = floatval($value);
            } else {
                $num = intval($value);
            }
            if (strval($num) === $value) {
                $value = $num;
            }
        }
        set_nested_value($input, $keys, $value);
    }
    return $input;
}
1
Rycochet

Je poste la fonction .ajax () de Jquery. J'essayais de récupérer mes données depuis $_POST mais elles étaient incomplètes. Ensuite, j'ai trouvé ce post qui m'a mis sur la bonne voie. Cependant, la méthode getRealPOST () décrite ci-dessus ne fonctionnait pas pour moi. Elle ne gère pas très bien les tableaux multidimensionnels et imbriqués. Au lieu de cela, j'ai utilisé la méthode parse_str() de PHP qui a fait l'affaire et qui a été un peu plus propre:

$rawdata = file_get_contents('php://input');
$urldecoded = urldecode($rawdata);
parse_str($urldecoded, $parsed);

$data = $parsed['data'];

(Dans mon JS, je publie un objet dont la charge est dans la propriété data. Le vôtre serait probablement différent.)

Je suis également allé dans mon php.ini et j'ai lancé max_memory et max_input_vars, mais cela ne semblait pas résoudre mon problème. J'ai également passé un certain temps à chasser le rouge parce que j'utilisais mon journal d'erreurs pour imprimer les données brutes et j'avais oublié que error_log avait une limite quant au nombre de caractères à imprimer, à moins que vous ne pensiez à l'augmenter. 

Quoi qu'il en soit, espérons que cela aidera toutes les personnes qui se retrouvent aux prises avec ce problème. 

1
Ian

Pour référence future: Sur une machine Ubuntu, je suis aux prises avec ce problème depuis assez longtemps et j’avais l’habitude d’adopter une solution de contournement semblable à celle décrite ci-dessus pour sauver la situation. J'ai maintenant suivi le problème dans mon php.ini et je l'ai finalement trouvé conforme à max_input_nesting_level = 0 J'ai commenté la ligne ci-dessus, redémarré Apache et tout a été corrigé.

1
torillt

J'ai rencontré le même problème. Mon formulaire créait les éléments d'entrée dans une boucle. Jusqu'à 1 000 éléments d'entrée ont été publiés et print_r($_POST); a affiché toutes les valeurs publiées.

Lorsque les éléments d'entrée sous la forme numérotée au-dessus de 1 000, print_r($_POST) vient de disparaître. Comme si le formulaire n'était pas posté du tout. J'ai atteint votre page de stackoverflow.com par recherche google.

Oui, augmenter post_max_size, memory_limit etc. n'a rien résolu. J'ai l'expérience pratique que l'augmentation de memory_limit au-delà de 128M peut aussi être dangereuse. Une fois que notre serveur d’hébergement Apache en direct a été raccroché. J'étais l'expérimentateur :-)

max_input_vars était le seul facteur limitant. 

echo ini_get('max_input_vars');

a montré qu'il était 1000 par défaut . Étrangement, max_input_vars était absent du php.ini. Quoi qu'il en soit, j'ai ajouté 

max_input_vars=10000 

dans mon php.ini et redémarré Apache. 

Maintenant, echo ini_get('max_input_vars'); a montré qu'il était passé à 10000 et mes données de formulaire volumineuses pouvaient être interceptées après publication. Problème résolu.

Je vois que max_input_vars est de type PHP_INI_PERDIR. Ce qui signifie que je ne peux pas changer sa valeur pour la page php individuelle où j'ai besoin d'une valeur plus élevée en utilisant ini_set ('max_input_vars', 10000);

1

J'ai eu un problème similaire et la modification de MAX_INPUT_VARS a corrigé le problème. 

Cela vaut la peine de vérifier ce que vous envoyez et ce qui est reçu. Dans mon cas, l'appel AJAX contenait un tableau formaté de toutes les valeurs sauf VAR_DUMP ($ this-> input-> post ()); a révélé des valeurs manquantes. 

Donc, la réponse évidente était comme quelqu'un l'a dit ici - max_input_vars. 

0
Jamie Fuller

J'ai trouvé cette réponse via une recherche et je devais proposer un autre problème. Dans mon cas, mon message n'était pas trop volumineux, et pourtant la valeur que je soumettais sur le terrain ne figurait pas dans le tableau $ _POST. Il s’est avéré que j’ai accidentellement eu un autre champ plus bas dans ma fiche avec le même nom. Alors:

<form>
   <input type="text" name="field1">
   <input type="text" name="field2">
   <input type="text" name="field3">
   <input type="text" name="field1">
   <input type="submit">
</form>

Lorsque la variable $_POST est remplie avec les données de ce formulaire, la valeur de votre premier champ sera remplacée par la valeur de ce dernier champ portant le même nom. Si le premier champ est obligatoire et que vous remplissez une valeur, mais que le dernier champ n'est pas obligatoire et qu'il est soumis à vide, vous verrez des symptômes similaires à cette question, car la valeur $ _POST ['field1'] affichera la valeur du dernier élément de votre formulaire qui est vide.

TLDR:

Assurez-vous de vérifier les noms de champs en double dans votre formulaire!

0
Jeremy Harris

utiliser cette fonction pour obtenir de vraies données

function get_real_post() {

    function set_nested_value(&$arr, &$keys, &$value) {
        $key = array_shift($keys);
        if (count($keys)) {
            // Got deeper to go
            if (!array_key_exists($key, $arr)) {
                // Make sure we can get deeper if we've not hit this key before
                $arr[$key] = array();
            } elseif (!is_array($arr[$key])) {
                // This should never be relevant for well formed input data
                throw new Exception("Setting a value and an array with the same key: $key");
            }
            set_nested_value($arr[$key], $keys, $value);
        } elseif (empty($key)) {
            // Setting an Array
            $arr[] = $value;
        } else {
            // Setting an Object
            $arr[$key] = $value;
        }
    }

    $input = array();
    $parts = array();

    $rawdata=file_get_contents("php://input");
    $rawdata=urldecode($rawdata);
    $pairs = explode("&", $rawdata);
    foreach ($pairs as $pair) {
        $key_value = explode("=", $pair, 2);
        preg_match_all("/([a-zA-Z0-9_]*)(?:\[([^\[\]]*(?:(?R)[^\[\]]*)*)\])?/", urldecode($key_value[0]), $parts);
        $keys = array($parts[1][0]);
        if (isset($parts[2][0])&&$parts[2][0]!="") {
            array_pop($parts[2]); // Remove the blank one on the end
            $keys = array_merge($keys, $parts[2]);
        }
        $value = urldecode($key_value[1]);
        if ($value == "true") {
            $value = true;
        } else if ($value == "false") {
            $value = false;
        } else if (is_numeric($value)) {
            if (strpos($value, ".") !== false) {
                $num = floatval($value);
            } else {
                $num = intval($value);
            }
            if (strval($num) === $value) {
                $value = $num;
            }
        }
        set_nested_value($input, $keys, $value);
    }
    return $input;
}
0
morteza khadem

J'ai rencontré le même problème et j'ai trouvé une solution très utile sans augmenter la taille ou la limite dans le fichier .ini . Nous savons que max_input_vars = 1000 par défaut et qu'il s'agit de prefect . Il suffit de concaténer une valeur de tableau Précisez votre nombre de variables sous 1000 . Chaque nom de variable compte un et non ses valeurs . Par exemple:

<code>
$i = 10; //counts 1
$i = array(1,2,3,4,5); //counts 5
</code>

Tu peux le faire:

<code>
$i = 1_2_3_4_5; // counts 1
</code>

J'espère comprendre.

0
Manish Shukla