За последние 24 часа нас посетили 18684 программиста и 1690 роботов. Сейчас ищут 1266 программистов ...

Не могу разобраться, нужна помощь

Тема в разделе "Сделайте за меня", создана пользователем Serege555, 31 авг 2015.

  1. Serege555

    Serege555 Новичок

    С нами с:
    14 фев 2015
    Сообщения:
    25
    Симпатии:
    0
    Всем привет!!!

    Давно мучаюсь с обработкой данных полученных из глобальных массивов $_GET, $_POST, $_COOKIE, $_SESSION.
    Подскажите как обычно "очищаются" данные из этих массивов перед использованием?

    Как делаю я:
    1. Есть класс, который "приводит" полученные данные к нужным мне стандартам, например
    Код (PHP):
    1.     final class Clear {
    2.  
    3.         public static function clearVar($value, $case = false) {
    4.  
    5.             switch ($case) {
    6.  
    7.                     # ---- Нижний регистр ----
    8.  
    9.                 case 1:
    10.                     $value = self::defaultMethod($value);
    11.                     $value = mb_convert_case($value, MB_CASE_LOWER);
    12.                     break;
    13.  
    14.                     # ---- Первая буква каждого слова заглавная ----
    15.  
    16.                 case 2:
    17.                     $value = self::defaultMethod($value);
    18.                     $value = mb_convert_case($value, MB_CASE_TITLE);
    19.                     break;
    20.  
    21.                     // И т.д.
    22.  
    23.                     # ---- По умолчанию ----
    24.  
    25.                 default:
    26.                     $value = self::defaultMethod($value);
    27.                     break;
    28.  
    29.                     # ----------------------
    30.             }
    31.  
    32.             return $value;
    33.         }
    34.  
    35.         private static function defaultMethod($value) {
    36.             $value = strip_tags($value);                                                # Удаление HTML и PHP-тегов
    37.             $value = htmlspecialchars($value);                                    # Замена HTML тегов на спецсимволы
    38.             $value = preg_replace(self::REG_001, ' ', $value);    # Удаление дублирующихся пробелов
    39.             $value = trim($value);                                                            # Удаление пробелов из конца и начала
    40.  
    41.             return $value;
    42.         }
    43.     }
    2. В самом "начале" загрузки страницы index.php перебираю нужный массив, например $_POST
    Код (PHP):
    1.             foreach ($_POST as $k => $v) {
    2.                     if (preg_match("/_([0-9]+)$/i", $k, $m))
    3.                         $v = Clear::clearVar($v, $m[1]);
    4.                     else
    5.                         $v = Clear::clearVar($v);
    6.  
    7.                                 $_POST[$k] = $v;
    8.             }
    И дальше уже "спокойно" использую $_POST.

    Т.е. если я хочу, чтобы например "имя пользователя" было в нижнем регистре, то в HTML я пишу:
    Код (Text):
    1.  
    2. <input name="userName_1" />
    А использую так:
    Код (PHP):
    1. Здравствуйте <?=$_POST['userName_1']?>, добро пожаловать в Личный кабинет.
     
  2. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
  3. Serege555

    Serege555 Новичок

    С нами с:
    14 фев 2015
    Сообщения:
    25
    Симпатии:
    0
    У меня это есть в классе Clear и методе defaultMethod
    Вопрос немного не в этом.

    Добавлено спустя 16 минут 9 секунд:
    Вместо пункта "2" (в первом сообщении) я использую класс:
    Код (PHP):
    1.     final class GlobalArray {
    2.  
    3.         public static function clear($a, $t) {
    4.             static $keys;
    5.  
    6.             foreach ($a as $k => $v) {
    7.                 $keys[] = $k;
    8.  
    9.                 if (is_array($v))
    10.                     self::clear($v, $t);
    11.                 else {
    12.                     if (preg_match("/_([0-9]+)$/i", $k, $m))
    13.                         $v = Clear::clearVar($v, $m[1]);
    14.                     else
    15.                         $v = Clear::clearVar($v);
    16.  
    17.                     switch (count($keys)) {
    18.                         // Одномерный массив
    19.                         case 1:
    20.                             switch ($t) {
    21.                                 case '_GET': $_GET[$keys[0]] = $v;
    22.                                 case '_POST': $_POST[$keys[0]] = $v;
    23.                                 case '_COOKIE': $_COOKIE[$keys[0]] = $v;
    24.                                 case '_SESSION': $_SESSION[$keys[0]] = $v;
    25.                             }
    26.                             break;
    27.                         // Двухмерный массив
    28.                         case 2:
    29.                             switch ($t) {
    30.                                 case '_GET': $_GET[$keys[0]][$keys[1]] = $v;
    31.                                 case '_POST': $_POST[$keys[0]][$keys[1]] = $v;
    32.                                 case '_COOKIE': $_COOKIE[$keys[0]][$keys[1]] = $v;
    33.                                 case '_SESSION': $_SESSION[$keys[0]][$keys[1]] = $v;
    34.                             }
    35.                             break;
    36.                         // Трехмерный массив
    37.                         case 3:
    38.                             switch ($t) {
    39.                                 case '_GET': $_GET[$keys[0]][$keys[1]][$keys[2]] = $v;
    40.                                 case '_POST': $_POST[$keys[0]][$keys[1]][$keys[2]] = $v;
    41.                                 case '_COOKIE': $_COOKIE[$keys[0]][$keys[1]][$keys[2]] = $v;
    42.                                 case '_SESSION': $_SESSION[$keys[0]][$keys[1]][$keys[2]] = $v;
    43.                             }
    44.                             break;
    45.                     }
    46.  
    47.                     $keys = array();
    48.                 }
    49.             }
    50.         }
    51.     }
    52.  
    Который я использую так:
    Код (PHP):
    1.             GlobalArray::clear($_GET, '_GET');
    2.             GlobalArray::clear($_POST, '_POST');
    3.             GlobalArray::clear($_COOKIE, '_COOKIE');
    4.             GlobalArray::clear($_SESSION, '_SESSION');
    5.  
    Проблема в том, что приходится "определять" какой именно массив я "очищаю". case '_GET', case '_POST'.
    Пробовал передавать массив по ссылке, но тогда "чистится" только одномерный массив.

    Пробовал использовать второй передаваемый параметр, как название массива, например:
    Код (PHP):
    1. $name = '_POST';
    2. ${$name}[$keys[0]] = $v;
    Но так тоже "не прокатывает", т.к. это работает только с "новой" переменной, а массивы уже "создаются" заранее (до этого кода).
     
  4. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Ты приводишь данные к нужному тебе формату. В чем вопрос?
    Если только в этом, то ответ - никак.
    Чаще всего данные валидируются и обрабатываются.
    Суть первого заключается в проверке на соответствие формату. Если у тебя в логине разрешены только буквы, цифры и подчеркивание, ты проверяешь введенный логин и выводишь сообщение об ошибке, если он не соответствует формату. А не подстраиваешь его под формат.
    Если это не логин, а например, сообщение, то разумнее его обработать с помощью htmlspecialchars перед отображением (а не перед записью в базу), чтобы пользователи видели именно то, что вводят, а в базу сохранилось именно то, что ввел пользователь. А не удалять теги и неподходящие символы.

    Для защиты нужны всего две функции: htmlspecialchars (от XSS) и mysql_real_escape_string (или аналогичная, от инъекций).
     
  5. Serege555

    Serege555 Новичок

    С нами с:
    14 фев 2015
    Сообщения:
    25
    Симпатии:
    0
    А как тогда проверять скажем цену товара?
    Пользователь вводит "1500,00", а мне нужно (для записи в таблицу) "1500.00", т.е. если есть запятые, то заменить их на точки.
    И допустим у меня 2 поля:
    - цена товара
    - цена товара со скидкой
    И получается мне нужно написать 2 валидатора с одним и тем же кодом по замене запятых на точки.
    Один валидатор не прокатит, т.к. в одном мне нужно в случае неверного ввода сказать, "введи правильно цену товара", а в другом "введи правильно цену товара со скидкой", а таких полей может быть не 2шт.

    Добавлено спустя 9 минут 11 секунд:
    А так я заранее во всех "ценах" в инпуте допишу скажем "название_5", т.е. "цена_5", "цена_со_скидкой_5" и во всех их "заранее" перед валидацией заменю запятые на точки, удалю пробелы слева и справа и скажем приведу к типу float. И в валидаторе нужно будет проверить только мин. длину, макс. длину.
     
  6. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Конкретно в этой ситуации можно использовать
    Код (Text):
    1. <input type="number" steps="0.01" name="price">
    хотя в это поле можно вписать запятую, при отправке будет точка.
    Валидация так же снижает риск ошибки. Пользователь мог перепутать поля и ввести не те данные. Если ты молча отфильтруешь их, сохранится ерунда.

    Добавлено спустя 1 минуту 2 секунды:
    Использование специальных типов полей не избавляет от необходимости валидации. Они предназначены, чтобы пользователю было легче ввести данные правильно.

    Добавлено спустя 2 минуты 23 секунды:
    Еще в HTML 5 можно валидировать с помощью регулярки прямо в HTML, без скриптов и отправки формы.
    http://www.htmlgoodies.com/html5/markup/telerik-takes-cross ... lease.html
     
  7. Serege555

    Serege555 Новичок

    С нами с:
    14 фев 2015
    Сообщения:
    25
    Симпатии:
    0
    Согласен, можно поступить так.
    А что если у пользователя IE7?
    А что если он "злоумышленник" и отправит исправленную форму где не будет type="number" steps="0.01"?

    Вот еще пример: с названиями или заголовками или подзаголовками без разницы. У каждого из них будет свой валидатор (ну не совсем у каждого конечно). И пользователь написал HTML тэги, которые мне не нужны там совсем или "случайно" поставил кучу пробелов (пробел заело или скопировал текст из таблицы) какой здесь будет валидатор? Проверить мин. и макс. длину? А как же пробелы? Или во всех валидаторах писать один и тот же код по удалению пробелов, тэгов или еще чего?
    Я привожу такие примеры так как, пример с "логином" очень простой (хотя опять же и в нем могут быть пробелы). Пользователь скопировал свой логин из таблицы .xls (хранит он их там) и вставил. Валидатор ему скажет: "Не верно введен логин" или даже так "Не верно введены логин или пароль". А введено все верно, всего лишь пробел в конце один (незаметный) и пользователь думает, логин верный, ну тогда с паролем косяк получается... Понимаете о чем я?

    Тогда и в валидаторе логина нужно опять же в 10-ый или 20-ый раз как и в других валидаторах удалить пробелы слева и справа, удалить тэги (мало ли от куда он его скопировал).

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

    Добавлено спустя 11 минут 11 секунд:
    Кстати "хорошее", вернее более подходящее слово "фильтр", вместо чистки.

    Ерунда кстати тоже сохраниться не может, например если мне в этой переменной нужно число, то максимум, что я получу, так это "0", так как после фильтрации "по умолчанию" Clear::defaultMethod() я умножу эти данные на 1 или приведу их к типу integer. И уже 0 не пройдет валидацию и не будет записан в таблицу.

    Кстати я не писал, что НЕ использую валидации. Использую, но после фильтрации.
     
  8. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    т.е. в любом случае надо проверять на сервере.
    значит надо ему сказать, что скобки < > запрещены. Хотя если у тебя не HTML-редактор, то это и не теги вовсе, а просто текст, который в любом случае перед отображением надо прогонять через htmlspecialchars, чтобы где-нибудь разметка не поехала, из-за попадания кавычки в alt картинки. А после htmlspecialchars теги работать не будут, так зачем их вырезать? Пускай пользователь видит то, что ввёл.

    на счет trim, пожалуй, соглашусь.
    А вот то, что ноль - не число, это редкий случай. И еще php делает так:
    Код (Text):
    1. $a = '33 коровы';
    2. echo $a * 1; // 33
     
  9. Serege555

    Serege555 Новичок

    С нами с:
    14 фев 2015
    Сообщения:
    25
    Симпатии:
    0
    Верно

    Не соглашусь.
    Зачем ему эта "лишняя" информация?
    Пользователь добавляет новый товар например, скопировал его название от куда нибудь, вставил в поле. Предположим, что там были тэги (или еще то, что там быть не должно), зачем ему про это говорить?
    Он нажимает кнопку "Сохранить" и видит: "Такие то символы запрещены (и далее идет их перечисление)".
    Он удаляет символы, снова нажимает кнопку и тут опять: "Такие то символы запрещены" (ну не увидел он несколько:)))).
    Находит их и удаляет и опять: "Вы все еще не все запрещенные символы удалили, типа смотрите ВНИМАТЕЛЬНЕЕ".
    Что после этого он подумает не трудно догадаться...
    Проще всю эту "рутинную" работу сделать ЗА него. PHP ведь не "влом".

    Где они нужны, там их никто не собирается удалять.
    Просто добавляем в switch новый кейс, у которого номер будет (какой там следующий?), пускай 8. И текстовое поле называем "название_8".
    В кейсе будет htmlspecialchars, удаление двойных и более пробелов и trim (куда же без него). Метод defaultMethod использоваться не будет.
    И теперь во всех полях, где нужно сохранить тэги к названию будем дописывать "_8".

    Да не редкий. Опять же "цена товара". Вот захотел я чтобы можно было добавлять товары с ценой.
    Валидатору нужно будет проверить:
    - не пустое ли поле?
    - число больше нуля?
    И если пользователь введет текст, то до валидатора "дойдет" только 0.
    А если "33 коровы", то 33. Все правильно делает php, мы получили число, что и хотели для поля цены товара.