2010-11-25 7 views
2

J'ai un objet de PHP, dont les propriétés sont initialisés de la façon suivante:comportement Erratic lorsque l'on compare PHP implosé tableaux avec des valeurs de champ de formulaire en utilisant JavaScript

$this->contact = implode(PHP_EOL,$description->getContact()) . PHP_EOL; 

Les seules exceptions sont deux propriétés nommées la version et bugs.

Cet objet est ensuite codé dans un objet JSON et transmis au javascript suivant, qui compare l'objet JSON avec la valeur d'un formulaire.

function compareEntry(data){ 
     var dataProperties = ["version", "bugs", "scenario", "exception", "instruction", "sources", "risks", "test", "contact"]; 
     var hasChanged = false; 

     for(var i = 0; i < dataProperties.length; i++){ 
      var dataProperty = dataProperties[i]; 
      alert("Original: '" + data[dataProperty] + "'\nModified: '" + document.myform[dataProperty].value + "'\nTest Value: " + (!data[dataProperty].localeCompare(document.myform[dataProperty].value))); 
      if(!data[dataProperty].localeCompare(document.myform[dataProperty].value)){ 
       hasChanged = true; 
      } 
     } 
[...] 

Dans l'exception de la version et bogues, toutes les autres propriétés sont comparées à la valeur dans la zone de texte.

Les champs de formulaire sont initialisés avec la valeur de l'objet PHP. Lorsque je soumets le formulaire, la fonction est appelée. Si je soumets le formulaire sans changer aucune valeur, il me donne quand même un false en comparant une propriété avec la valeur d'une zone de texte. Pourquoi et comment pourrais-je les comparer correctement?

Remarques: L'objet PHP est le reflet d'une entrée MySQL créée avec le même formulaire. Entre les deux, l'information a été chiffrée et déchiffrée. Mais il ne devrait pas jouer de rôle, car l'objet PHP/JSon et la valeur initiale du formulaire proviennent de la même source.

EDIT

Après l'explication de Frode, j'ai changé ma déclaration de test à:

data[dataProperty].localeCompare(document.myform[dataProperty].value)!=0 

Mais après, je note deux discordances.

  • Propriétés Version et bogues qui jusque-là sont retournés true lorsque le retour testé maintenant false. Mais contrairement aux autres propriétés, je ne manipule pas les valeurs lorsque je les récupère de la base de données. La valeur de la version de la propriété est stockée dans une balise select dans le formulaire.
  • Et plus étrange, quand je change l'une des valeurs dans la zone de texte, au lieu de me donner false, il me donne true.

Il m'est apparu que cela peut être dû à l'implémentation de javascript du navigateur que j'utilise. Mais le résultat que j'ai obtenu n'est pas tout à fait comme je l'espérais. Considérant que, j'ai le comportement décrit dans Firefox et Chrome, IE et Opera jeter toujours false (à l'exception notable de la comparaison version, qui m'a donné vrai dans IE, bien qu'il ne pouvait pas récupérer la valeur de la select tag). Dois-je utiliser une autre méthode pour comparer mes chaînes de caractères?

EDIT 2

Après avoir pris la suggestion de Wolph, j'ai changé la condition de test:

données [dataProperty] .trim() document.myform [dataProperty] .trim()

Où trim() est la fonction décrite dans this other question. Et le résultat est l'inverse de ce que j'avais dans le premier EDIT. Sauf pour Chrome qui semble attribuer son booléen au hasard. Il semble y avoir quelque chose qui ne va vraiment pas dans mes données.

Voici un exemple d'un objet JSON tel que je peux le voir dans Firefox (variable data dans l'extrait de code).

{"version":"REL-773","bugs":"20831","scenario":"THIS IS A TEST\r\n\r\nThis is the what happens: stuffs.\r\n","exception":"N\/A\r\n","instruction":"1. First Step.\r\n2. Second Step.\r\n2. Third Step\r\nIt is longer.\r\n4. Fourth Step.\r\n5. Fifth Step.\r\n6. Sixth Step.\r\n","sources":"me\r\n","risks":"High risks as it is just for testing of the web application.\r\n","test":"1. Select an entry\r\n2. Change some data such as <HOME>\/path\/\r\n3. See if the application run as expected!\r\n","contact":"[email protected]\r\n"} 

EDIT 3

Utilisation de la fonction escape() pour échapper à tous les caractères spéciaux des deux chaînes, je remarquai que dans le caractère %OA est écrit comme %OD%OA dans l'objet JSON. Il m'a fait soupçonner que ma fonction de coupe ne remplace pas correctement le \r\n par \n. (. Fonction de coupe que j'ai ajouté après la suggestion des affiches ici)

Voici la fonction que j'utilise:

if(typeof(String.prototype.trim) === "undefined") 
{ 
    String.prototype.trim = function() 
    { 
     return String(this).replace(/^\s+|\s+$/g, '').replace(/\r\n/g,"\n"); 
    }; 
} 
+0

Avez-vous essayé d'effacer tous les espaces avant de comparer? – Wolph

+0

@WoLpH, il semble que l'effacement des espaces blancs n'aide pas un peu. – Eldros

+0

Ok ... deuxième estimation (toujours liée aux espaces), dans votre testdata je vois '\ r \ n' qui est le format de nouvelle ligne de Windows. Il se peut que ce soit simplement au format '\ n'. Essayez donc de supprimer tous les caractères '\ r' avant de comparer. – Wolph

Répondre

1

string.localeCompare de Javascript retourne 0 si les chaînes comparées sont identiques, et -1 ou 1 autre . Ainsi, votre article si:

if(!data[dataProperty].localeCompare(document.myform[dataProperty].value)){ 
    hasChanged = true; 
} 

.. sera en fait ensemble hasChanged true lorsque les chaînes sont égales. Essayez de supprimer le! et voyez s'il se comporte comme vous l'espérez.

+0

merci, je n'ai pas remarqué ça ... Après tant de problèmes complexes pris en charge aujourd'hui, j'ai dû trébucher sur cette petite chose. Cependant, il semble que le problème soit plus complexe qu'on le pensait. – Eldros

+0

Accrochez-vous là-bas, seulement un jour jusqu'au week-end. Cela peut être utile si vous montrez un exemple de JSON réel et les champs/valeurs de formulaire qui l'accompagnent. Toutes les chaînes de valeurs sont-elles? Des espaces de fin? – Frode

+0

oui les valeurs sont des chaînes, afaik. Et il y avait des espaces traînants, mais j'ai essayé de les dépouiller et ça n'a pas vraiment fait de différence. – Eldros

2

Tout d'abord, Désistement: J'ai le sentiment que ce n'est peut-être pas la réponse définitive, mais plutôt une solution de contournement. Comme c'est la seule façon de traiter ce problème. Maintenant que j'avais posté cette question, j'ai appris que client-side form validation is not enough. Non seulement cela ne suffit pas, mais dans mon cas, ce n'est pas nécessaire car cela n'apporterait rien dans l'expérience utilisateur pour savoir qu'une valeur a été modifiée. Il est beaucoup plus intéressant pour l'utilisateur de savoir qu'une valeur n'est pas bien formatée ou tout simplement erronée. J'ai donc migré la vérification de comparaison vers le serveur.

D'abord, j'encase mes informations PHP dans une chaîne JSON, en étant sûr d'échapper tous les caractères pertinents. Je me suis d'abord assuré que le symbole de citation était correctement échappé, puis j'ai remplacé characters which could be problematic par son équivalent unicode, avant de mettre la chaîne résultante dans une entrée cachée de mon formulaire.

//escaping ",' and other throublesome characters properly for json 
$json_string = str_replace('\'', "\\'", json_encode($objEncasing)); 
$json_string = str_replace(array('\\"', '\\\'', '&','<','>'), array('\\u0022', '\\\u0027', '\\u0026', '\\u003C', '\\u003E'), $json_string); 
echo "<input name='json' type='hidden' value='".$json_string."' />"; 

Il faut noter que l'objet JSON correspondent aux informations avant toute modification sont faits sous la forme, donc pourquoi la chaîne JSON est formaté en PHP. Les informations de formulaire sont ensuite envoyées via POST à ​​un nouveau script qui fera tout le travail nécessaire.

Maintenant première chose que je fais dans le script de réception, est de récupérer la variable JSON, mais il ne faut pas oublier de check for magic quotes:

if(get_magic_quotes_gpc()){ 
    $json_string = stripslashes($_POST['json']); 
}else{ 
    $json_string = $_POST['json']; 
} 

Maintenant, pour convertir l'objet JSON dans un tableau et vous pouvez comparer au tableau de $ _POST (à l'exception de la valeur JSON):

if(!empty($json_string)){ 
    $json_encasing = json_decode($json_string, true); 
    $gotChange = false; 

    foreach($_POST as $key => $value){ 
     if($key != "json"){ 
      //Compare the value, if something change set $gotChange to true 
      $value = stripslashes($value); 
      if($value != $json_encasing[$key]){ 
        $json_encasing[$key] = $value; 
        $gotChange = true; 
      } 
     } 
    } 

    if($gotChange){ 
     //Do your stuff 
    } 
} 

Comme je le fais sur mon serveur, je ne ai pas besoin d'anticiper plusieurs comportements différents. Donc, mon conseil est, si vous pouvez l'aider, faites vos choses côté serveur.