开发者

Erratic behaviour when comparing PHP imploded arrays with form field values using JavaScript

I've got a PHP Object, whose properties are initialized the following way:

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

The only exceptions are two properties named version and bugs.

This object is then encoded into a JSON object and passed into the following javascript, which compare the JSON object with value from a form.

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;
            }
        }
[...]

In the exception of version and bugs, all other properties are compared with the value in the textarea.

The form fields are initialized with the value of the PHP object. When I submit the form the function is called. If I submit the form without changing any value, it still give me a false when comparing a property with the value of a textarea. Why and how could I correctly compare them?

Notes: The PHP Object is a reflection of a MySQL entry which was created with the same form. In between, the information was encrypted and decrypted. But it shouldn't play a role, because the PHP/JSon object and the initial value of the form are from the same source.

EDIT

After the explanation of Frode, I changed my testing statement to:

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

But afterwards I noted two discrepencies.

  • Properties version and bugs which until then returned true when tested return now false. But in the contrary to the other properties, I don't manipulate the values when I'm retrieving them from the database. The value of the property version is stored in a select tag in the form.
  • And weirder is, when I'm changing one of the value in the textarea, instead of giving me false, it gives me true.

It occured to me that it may be due to the implementation of javascript of the browser I use. But the result I got is not quite as I expected it. Whereas, I've got the described behaviour in Firefox and Chrome, IE and Opera throw always false (with the notable exception of the comparing the version, which gave me true in IE, although he couldn't retrieve the value of the select tag).

Should I maybe use some other method to compare my strings?

EDIT 2

After taking the suggestion of WoLpH, I changed the test condition to:

data[dataProperty].trim() document.myform[dataProperty].trim()

Where trim() is the function described in this other question. And the result are the inverse of what I had in the first EDIT. Except for Chrome who seems to assign it's boolean in random. There seems to be something really wrong in my data in a way.

Here is an example of a JSON object as I can see it in Firefox (variable data in the code snippet).

{"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":"me@web.de\r\n"}

EDIT 3

Using the function escape() to escape all special characters of the two strings, I noticed that in the character %OA is written as %OD%OA in the JSON object. It made me suspect that my trimming function doesn't replace correctly the \r\n by \n. (trimming function that I added after the suggestion of the posters here.)

Here is the function I us开发者_开发百科e:

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


First, Disclaimer: I have the feeling that maybe this isn't the definite answer but more of a workaround. As this is the only way I could deal with this problem.

Now, since I had posted this question, I learned that client-side form validation is not enough. Not only it not enough, but in my case it is not needed as it wouldn't bring anything in the user experience to know that a value has been changed. It is much more interesting for the user to know that a value is not well formatted or just plain wrong. So I migrated the comparison check to the server side.

First I encase my PHP information in a json string, being sure to escape all the relevant characters. I first ensured that the quote symbol was escape correctly, and then I replaced characters which could be problematic by there unicode equivalent, before putting the resulting string in a hidden input of my form.

//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."' />"; 

One should note that the json object correspond to the information before any change are made in the form, thus why the json string is formatted in PHP. The form information is then sent through POST to a new script which will do all the necessary work.

Now first thing I do in the receiving script, is retrieve the json variable, but one should not forget to check for magic quotes:

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

Now to convert the json object into an array and the you can compare it to the $_POST array (with the exception of the json value):

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
    }
}

As I'm doing that on my Server, I don't need to anticipate several different behaviour. So my advice is, if you can help it, do your stuff server-side.


Javascript's string.localeCompare returns 0 if the strings compared are identical, and -1 or 1 otherwise. So your if clause:

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

.. will in fact set hasChanged to true when the strings are equal. Try removing the ! and see if it behaves as you expect.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜