Неустойчивое поведение при сравнении PHP-массивов со значениями полей формы с использованием JavaScript - PullRequest
2 голосов
/ 25 ноября 2010

У меня есть объект PHP, свойства которого инициализируются следующим образом:

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

Единственными исключениями являются два свойства с именами версия и ошибки .

Этот объект затем кодируется в объект JSON и передается в следующий javascript, который сравнивает объект JSON со значением из формы.

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

За исключением версии и ошибки , все остальные свойства сравниваются со значением в текстовой области.

Поля формы инициализируются со значением объекта PHP.Когда я отправляю форму, функция вызывается.Если я отправляю форму без изменения какого-либо значения, она все равно дает false при сравнении свойства со значением текстовой области.Почему и как я могу их правильно сравнить?

Примечания: Объект PHP является отражением записи MySQL, созданной в той же форме.В промежутке информация была зашифрована и расшифрована.Но это не должно играть роли, потому что объект PHP / JSon и начальное значение формы взяты из одного источника.

EDIT

После объясненияиз Frode, я изменил свой тестовый отчет на:

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

Но потом я заметил две несоответствия.

  • Свойства версия и ошибки которые до этого вернули true при тестировании вернули сейчас false.Но в отличие от других свойств, Я не манипулирую значениями при извлечении их из базы данных. Значение версии свойства сохраняется в теге select в форме.
  • И страннее, когда я меняю одно из значений в текстовой области, вместо того, чтобы дать мне false, он дает мне true.

Это произошломне, что это может быть связано с реализацией JavaScript браузера, который я использую.Но результат, который я получил, не совсем такой, как я ожидал.Принимая во внимание, что у меня есть описанное поведение в Firefox и Chrome, IE и Opera бросают всегда false (с заметным исключением сравнения версии , которая дала мне истину в IE, хотя он не мог 't получить значение тега select).

Должен ли я использовать какой-либо другой метод для сравнения моих строк?

РЕДАКТИРОВАТЬ 2

Приняв предложение WoLpH, я изменил условие теста на:

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

Где trim () - этофункция описана в этот другой вопрос .И результат обратен тому, что я имел в первом редактировании.За исключением Chrome, который, кажется, назначает его логическое значение случайно.Кажется, что-то действительно не так в моих данных.

Вот пример объекта JSON, который я вижу в Firefox (переменная data во фрагменте кода).

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

РЕДАКТИРОВАТЬ 3

Используя функцию escape() для экранирования всех специальных символов двух строк, я заметил, что в символе %OA написанокак %OD%OA в объекте JSON.Это заставило меня подозревать, что моя функция обрезки неправильно заменяет \r\n на \n.(Функция обрезки, которую я добавил после предложения постеров здесь.)

Вот функция, которую я использую:

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

Ответы [ 2 ]

2 голосов
/ 08 сентября 2011

Во-первых, Отказ от ответственности : У меня такое ощущение, что, возможно, это не определенный ответ, а скорее обходной путь. Поскольку это единственный способ решить эту проблему.

Теперь, так как я разместил этот вопрос, я узнал, что проверки на стороне клиента недостаточно . Мало того, что этого недостаточно, но в моем случае это не нужно, так как это ничего не даст пользователю, чтобы знать, что значение было изменено. Пользователю гораздо интереснее знать, что значение не очень хорошо отформатировано или просто неверно. Поэтому я перенес проверку сравнения на серверную часть.

Сначала я заключаю информацию о PHP в строку json, чтобы избежать всех соответствующих символов. Сначала я удостоверился, что символ кавычки был экранирован правильно, а затем я заменил символов, которые могут быть проблемными , на их эквивалент в Юникоде, прежде чем поместить полученную строку в скрытый ввод моей формы.

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

Следует отметить, что объект json соответствует информации до внесения каких-либо изменений в форму, поэтому строка json отформатирована в PHP. Затем информация формы отправляется через POST в новый скрипт, который выполнит всю необходимую работу.

Теперь первое, что я делаю в принимающем скрипте, это извлекаю переменную json, но не следует забывать проверять магические кавычки :

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

Теперь, чтобы преобразовать объект json в массив и сравнить его с массивом $ _POST (за исключением значения 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
    }
}

Поскольку я делаю это на моем Сервере, мне не нужно предвидеть несколько другое поведение. Поэтому я советую, если вы можете помочь, делайте все на стороне сервера.

1 голос
/ 25 ноября 2010

Javascript string.localeCompare возвращает 0, если сравниваемые строки идентичны, и -1 или 1 в противном случае. Итак, ваше условие if:

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

.. фактически установит hasChanged в true, если строки равны. Попробуйте удалить! и посмотрите, будет ли он вести себя так, как вы ожидаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...