Windows        16.04.2024   

Php проверка существования переменной. Variables if - PHP:проверьте, существует ли переменная, но также имеет значение, равное чему-то

Материал предназначен в основном для начинающих веб-программистов.

Введение.

Часто ко мне обращаются клиенты, у которых установлены самописные CMS или модули, написанные начинающими веб-программистами, которые не понимают, что нужно для защиты данных и зачастую копируют функции фильтрации, не задумываясь о том как они работают и что именно нужно с ними делать.

Здесь я постараюсь описать как можно подробнее частые ошибки при фильтрации данных в PHP скрипте и дать простые советы как правильно выполнить фильтрацию данных.

В сети много статей по поводу фильтрации данных, но они как правильно не полные и без подробные примеров.

Разбор полетов.

Фильтрация. Ошибка №1
Для числовых переменных используется такая проверка:
$number = $_GET["input_number"]; if (intval($number)) { ... выполняем SQL запрос... }
Почему она приведет к SQL инъекции? Дело в том, что пользователь может указать в переменной input_number значение:
1"+UNION+SELECT
В таком случаи проверка будет успешно пройдена, т.к. функция intval получает целочисленное значение переменной, т.е. 1, но в самой переменной $number ничего не изменилось, поэтому весь вредоносный код будет передан в SQL запрос.
Правильная фильтрация:
$number = intval($_GET["input_number"]); if ($number) { ... выполняем SQL запрос... }
Конечно, условие может меняться, например если вам нужно получить только определенный диапазон:
if ($number >= 32 AND $number <= 65)

Если вы используете чекбоксы или мультиселекты с числовыми значениями, выполните такую проверку:
$checkbox_arr = array_map("intval", $_POST["checkbox"]);
array_map
Так же встречаю фильтрацию в виде:
$number = htmlspecialchars(intval($_GET["input_number"]));
htmlspecialchars
Или:
$number = mysql_escape_string(intval($_GET["input_number"]));
mysql_escape_string

Ничего кроме улыбки это не может вызвать:)

Фильтрация. Ошибка №2.
Для стринг-переменных используется такая фильтрация:
$input_text = addslashes($_GET["input_text"]);
Функция addslashes экранирует спец. символы, но она не учитывает кодировку БД и возможен обход фильтрации. Не стану копировать текст автора, который описал данную уязвимость и дам просто ссылку Chris Shiflett (перевод можно поискать в рунете).

Используйте функцию mysql_escape_string или mysql_real_escape_string , пример:
$input_text = mysql_escape_string($_GET["input_text"]);
Если вы не предполагаете вхождение html тегов, то лучше всего сделать такую фильтрацию:
$input_text = strip_tags($_GET["input_text"]); $input_text = htmlspecialchars($input_text); $input_text = mysql_escape_string($input_text);
strip_tags - убирает html теги.
htmlspecialchars - преобразует спец. символы в html сущности.
Так вы защитите себя от XSS атаки, помимо SQL инъекции.
Если же вам нужны html теги, но только как для вывода исходного кода, то достаточно использовать:
$input_text = htmlspecialchars($_GET["input_text"]); $input_text = mysql_escape_string($input_text);

Если вам важно, чтобы значение переменной не было пустой, то используйте функцию trim , пример:
$input_text = trim($_GET["input_text"]); $input_text = htmlspecialchars($input_text); $input_text = mysql_escape_string($input_text);

Фильтрация. Ошибка №3.
Она касается поиска в БД.
Для поиска по числам используйте фильтрацию, описанную в первой ошибке.
Для поиска по тексту используйте фильтрацию, описанную во второй ошибке, но с оговорками.
Для того, чтобы пользователь не смог выполнить логическую ошибку, нужно удалять или экранировать спец. символы SQL.
Пример без доп. обработки строки:
$input_text = htmlspecialchars($_GET["input_text"]); // Поиск: "%" $input_text = mysql_escape_string($input_text);
На выходе у нас получится запрос вида:
... WHERE text_row LIKE "%".$input_text."%" ... // WHERE text_row LIKE "%%%"
Это значительно увеличит нагрузку на базу.
В своём скрипте я использую функцию, которая удаляет нежелательные мне символы из поиска:
function strip_data($text) { $quotes = array ("\x27", "\x22", "\x60", "\t", "\n", "\r", "*", "%", "<", ">", "?", "!"); $goodquotes = array ("-", "+", "#"); $repquotes = array ("\-", "\+", "\#"); $text = trim(strip_tags($text)); $text = str_replace($quotes, "", $text); $text = str_replace($goodquotes, $repquotes, $text); $text = ereg_replace(" +", " ", $text); return $text; }
Конечно, не все из выше перечисленных символов представляют опасность, но в моём случаи они не нужны, поэтому выполняю поиск и замену.
Пример использования фильтрации:
$input_text = strip_data($_GET["input_text"]); $input_text = htmlspecialchars($input_text); $input_text = mysql_escape_string($input_text);
Также советую сделать ограничение по количеству символов в поиске, хотя бы не меньше 3-х, т.к. если у вас будет большое количество записей в базе, то поиск по 1-2 символам будет значительно увеличивать нагрузку на БД.
Фильтрация. Ошибка №4.
Не фильтруются значения в переменной $_COOKIE . Некоторые думаю, что раз эту переменную нельзя передать через форму, то это гарантия безопасности.
Данную переменную очень легко подделать любым браузером, отредактировав куки сайта.
Например, в одной известной CMS была проверка, используемого шаблона сайта:
if (@is_dir (MAIN_DIR . "/template/" . $_COOKIE["skin"])){ $config["skin"] = $_COOKIE["skin"]; } $tpl->dir = MAIN_DIR . "/template/" . $config["skin"];
В данном случаи можно подменить значение переменной $_COOKIE["skin"] и вызвать ошибку, в результате которой вы увидите абсолютный путь до папки сайта.
Если вы используете значение куков для сохранения в базу, то используйте одну из выше описанных фильтраций, тоже касается и переменной $_SERVER .
Фильтрация. Ошибка №5.
Включена директива register_globals . Обязательно выключите её, если она включена.
В некоторых ситуациях можно передать значение переменной, которая не должна была передаваться, например, если на сайте есть группы, то группе 2 переменная $group должна быть пустой или равняться 0, но достаточно подделать форму, добавив код:

В PHP скрипте переменная $group будет равна 5, если в скрипте она не была объявлена со значением по умолчанию.
Фильтрация. Ошибка №6.
Проверяйте загружаемые файлы.
Выполняйте проверку по следующим пунктам:
  1. Расширение файла. Желательно запретить загрузку файлов с расширениями: php, php3, php4, php5 и т.п.
  2. Загружен ли файл на сервер move_uploaded_file
  3. Размер файла
Проверка. Ошибка №1.
Сталкивался со случаями, когда для AJAX запроса (например: повышение репутации) передавалось имя пользователя или его ID (кому повышается репутация), но в самом PHP не было проверки на существование такого пользователя.
Например:
$user_id = intval($_REQUEST["user_id"]); ... INSERT INTO REPLOG SET uid = "{$user_id}", plus = "1" ... ... UPDATE Users SET reputation = reputation+1 WHERE user_id = "{$user_id}" ...
Получается мы создаем запись в базе, которая совершенно бесполезна нам.
Проверка. Ошибка №2.
При выполнении различного рода действий (добавление, редактирование, удаление) с данными не забывайте проверять права пользователя на доступ к данной функции и дополнительные возможности (использование html тегов или возможность опубликовать материал без проверки).

Давно исправлял в одном модуле форума подобную ошибку, когда любой пользователь мог отредактировать сообщение администрации.

Проверка. Ошибка №3.
При использовании нескольких php файлов сделайте простую проверку.
В файле index.php (или в любом другом главном файле) напишите такую строчку перед подключением других php файлов:
define ("READFILE", true);
В начале других php файлов напишите:
if (! defined ("READFILE")) { exit ("Error, wrong way to file.
Go to main."); }
Так вы ограничите доступ к файлам.
Проверка. Ошибка №4.
Используйте хеши для пользователей. Это поможет предотвратить вызов той или иной функции путём XSS.
Пример составления хеша для пользователей:
$secret_key = md5(strtolower("http://site.ru/" . $member["name"] . sha1($password) . date("Ymd"))); // $secret_key - это наш хеш
Далее во все важные формы подставляйте инпут со значением текущего хеша пользователя:

Во время выполнения скрипта осуществляйте проверку:
if ($_POST["secret_key"] !== $secret_key) { exit ("Error: secret_key!"); }
Проверка. Ошибка №5.
При выводе SQL ошибок сделайте простое ограничение к доступу информации. Например задайте пароль для GET переменной:
if ($_GET["passsql"] == "password") { ... вывод SQL ошибки... } else { ... Просто информация об ошибке, без подробностей... }
Это позволит скрыть от хакера информацию, которая может ему помочь во взломе сайта.
Проверка. Ошибка №5.
Старайтесь не подключать файлы, получая имена файлов извне.
Например:
if (isset($_GET["file_name"])) { include $_GET["file_name"] .".php"; }
Используйте переключатель

null function (11)

У меня есть (или нет) переменная $_GET["myvar"] исходящая из моей строки запроса, и я хочу проверить, существует ли эта переменная, а также если значение соответствует чему-то внутри моего оператора if:

То, что я делаю и думаю, это не лучший способ сделать:

if(isset($_GET["myvar"]) && $_GET["myvar"] == "something") : сделать что-то

Это простой случай, но представьте себе, что нужно сравнить многие из этих переменных $myvar .

Answers

Это похоже на принятый ответ, но вместо этого использует in_array . Я предпочитаю использовать empty() в этой ситуации. Я также предлагаю использовать новое объявление строкового массива, которое доступно в PHP 5.4.0 +.

$allowed = ["something","nothing"]; if(!empty($_GET["myvar"]) && in_array($_GET["myvar"],$allowed)){..}

Вот функция для проверки сразу нескольких значений.

$arrKeys = array_keys($_GET); $allowed = ["something","nothing"]; function checkGet($arrKeys,$allowed) { foreach($arrKeys as $key) { if(in_array($_GET[$key],$allowed)) { $values[$key]; } } return $values; }

Я использую всю свою собственную полезную функцию exst (), которая автоматически объявляет переменные.

$element1 = exst($arr["key1"]); $val2 = exst($_POST["key2"], "novalue"); /** * Function exst() - Checks if the variable has been set * (copy/paste it in any place of your code) * * If the variable is set and not empty returns the variable (no transformation) * If the variable is not set or empty, returns the $default value * * @param mixed $var * @param mixed $default * * @return mixed */ function exst(& $var, $default = "") { $t = ""; if (!isset($var) || !$var) { if (isset($default) && $default != "") $t = $default; } else { $t = $var; } if (is_string($t)) $t = trim($t); return $t; }

Ну, вы можете обойтись, только if($_GET["myvar"] == "something") поскольку это условие предполагает, что переменная также существует. Если это не так, выражение также приведет к false .

Я думаю, что это нормально делать в условных выражениях, как указано выше. На самом деле никакого вреда.

Мой вопрос: существует ли способ сделать это без объявления переменной дважды?

Нет, нет способа сделать это правильно, не выполняя две проверки. Я тоже это ненавижу.

Один из способов обойти это - это импортировать все соответствующие переменные GET в одну центральную точку в массив или объект определенного типа (большинство из них MVC делают это автоматически) и устанавливают все свойства, которые необходимы позже. (Вместо доступа к переменным запроса через код.)

If (isset($_GET["myvar"]) == "something")

Благодаря Mellowsoon и Pekka, я сделал некоторые исследования здесь и придумал это:

  • Проверяйте и объявляйте каждую переменную как null (если это так) перед началом использования (как рекомендовано):
!isset($_GET["myvar"]) ? $_GET["myvar"] = 0:0;

* ok, это просто, но отлично работает, вы можете начать использовать переменную всюду после этой строки

  • Использование массива для всех случаев:
$myvars = array("var1", "var2", "var3"); foreach($myvars as $key) !isset($_GET[$key]) ? $_GET[$key] =0:0;

* после этого вы можете использовать свои переменные (var1, var2, var3 ... и т. д.),

PS: функция, получающая объект JSON, должна быть лучше (или простая строка с разделителем для взрыва / взрыва);

Лучшие подходы приветствуются:)

ОБНОВИТЬ:

Используйте $ _REQUEST вместо $ _GET, таким образом вы покрываете переменные $ _GET и $ _POST.

Isset($_REQUEST[$key]) ? $_REQUEST[$key] =0:0;

Решение, которое я нашел от игры, это сделать:

If($x=&$_GET["myvar"] == "something") { // do stuff with $x }

Как подскажите, вы можете рассмотреть этот подход:

Required = array("myvar" => "defaultValue1", "foo" => "value2", "bar" => "value3", "baz" => "value4"); $missing = array_diff($required, array_keys($_GET)); foreach($missing as $key => $default) { $_GET[$key] = $default ; }

Вы устанавливаете значения по умолчанию и устанавливаете не получаемые параметры в значение по умолчанию:)

К сожалению, это единственный способ сделать это. Но есть подходы к работе с большими массивами. Например, что-то вроде этого:

$required = array("myvar", "foo", "bar", "baz"); $missing = array_diff($required, array_keys($_GET));

Теперь переменная $ missing содержит список значений, которые требуются, но отсутствуют в массиве $ _GET. Вы можете использовать $ missing array для отображения сообщения посетителю.

Или вы можете использовать что-то вроде этого:

$required = array("myvar", "foo", "bar", "baz"); $missing = array_diff($required, array_keys($_GET)); foreach($missing as $m) { $_GET[$m] = null; }

Теперь каждый требуемый элемент имеет по умолчанию значение по умолчанию. Теперь вы можете использовать if ($ _ GET ["myvar"] == "something"), не беспокоясь о том, что ключ не установлен.

Обновить

Другим способом очистки кода будет использование функции, которая проверяет, установлено ли значение.

Function getValue($key) { if (!isset($_GET[$key])) { return false; } return $_GET[$key]; } if (getValue("myvar") == "something") { // Do something }

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

Function _FX($name) { if (isset($$name)) return $$name; else return null; }

то вы делаете _FX("param") == "123" , просто мысль

Я нашел (намного) лучший код, чтобы сделать это, если вы хотите проверить что-нибудь в .

If [[ $1 = "" ]] then echo "$1 is blank" else echo "$1 is filled up" fi

Почему все это? Все в существует в Bash, но по умолчанию оно пустое, поэтому test -z и test -n не могут вам помочь.

If [ ${#1} = 0 ] then echo "$1 is blank" else echo "$1 is filled up" fi

Можно проверить, существует ли данная переменная, (то есть инициализирована или она). Для этого используется функция:

Isset(переменная);

Если переменной в данный момент не существует (нигде ранее ей не присваивалось значение или она была удалена функцией unset () ), то функцияisset () возвращаетfalse , в противном случае –true :

$x = 5;

if (isset($x))

echo ‘< BR >Переменная $ x существует, ‘, “ее значение равно $ x < BR >”;

На экране появится:

Переменная $ x существует, ее значение равно 5

Важно помнить, что мы не можем использовать в программе неинициализированную переменную – это породит предупреждение со стороны интерпретатора PHP .

Чтобы выяснить, является ли значение переменнойпустым , используется функция:

empty( переменная);

Если значение переменной равно нулю ,“0”, NULL , пустой строке (“” ),false, переменная не объявлена или являетсяпустым массивом , то эта функция возвращаетtrue , в противном случае –false .

Чтобы проверитьтип переменной, используются функции:

Is_string(переменная);

is _ int (переменная);

is _ float (переменная);

is _ null (переменная);

is _ array (переменная);

is _ numeric (переменная); - если переменная является числовой (integer , float ) или строкой, содержащей только числа.

Эти функции возвращают true , если переменная имеет указанный тип.

Вывод данных

Бесформатный вывод

Бесформатный вывод строк или значений переменных осуществляется функцией:

echo список переменных;

echo строка;

где список переменных – имена выводимых переменных через запятые.

Если мы работаем с веб-браузером, то эта функция направляет вывод в клиентскую часть браузера (в его окно).

Как это уже было сказано, если в строке, заключенной в двойные кавычки, встречаются имена переменных, то на экран вместо этих имен выводятся соответствующие им значения. Более того, если в такой строке встречаются теги HTML (дескрипторы, заключенные в угловые скобки), то браузер отображает этотHTML -код так, как он должен это делать при интерпретацииHTML -документа:

$year = 2012;

$message = “ Желаю всем счастья !”;

echo “

Мои поздравления !

”;

echo “ Наступил $year год !
$message
”;

?>

На экран будет выведен заголовок уровня H 3 и последующее приветствие, причем слово “счастья!” будет выведено полужирным курсивом:

Мои поздравления!

Наступил 2012 год! Желаю всем счастья!

Так можно создавать динамические сайты.

Форматированный вывод

Форматированный вывод позволяет представлять выводимые числа в различных системах счисления, а в десятичной системе – в различных видах (форматах ). Он похож на форматированный вывод вСи и осуществляется функциями:

printf (“формат”, список вывода);

sprintf (“формат”, список вывода);

Первая функция выводит в окно браузера отформатированные данные и возвращает их количество.

Вторая функция только форматирует выводимые данные, но не выводит их.

Формат – это последовательность описателей преобразований для выводимых значений.

Описатель преобразований для каждого значения имеет вид:

% ЗаполнительВыравниваниеДлина.ТочностьТип

- Заполнитель – это символ, который будет использоваться для дополнения результата преобразования до заданнойдлины (по умолчанию –пробел ); если это другой символ, то перед ним ставится одинарная кавычка (апостроф ),

- Выравнивание – по умолчанию – поправому краю поля вывода; если стоит минус (- ), то полевому ,

- Длина – ширина поля вывода - количество знакомест, отводимых для вывода этого значения. Если выводимое значение содержит меньше знакомест, чем заданнаядлина , то оставшееся пространство будет заполненопробелами или символами заполнения,

- Точность – количество десятичных разрядов в дробной части числа,

- Тип – тип выводимого значения:

b двоичное ,

с символ ,

d целое в десятичной системе счисления,

е вещественное в экспоненциальной форме (с плавающей запятой),

f вещественное в форме с фиксированной запятой,

s строка ,

о целое в восьмеричной системе счисления,

x целое в 16-ричной системе счисления.

Пример:

php

$ zarp _1 = 6543.21;

$ zarp _2 = 45321.67;

$ fam _1 = "Балаганов";

$ fam _2 = "Бендер";

printf ("< H 1>Платежная ведомость h 1>");

printf("%".-12s%".10.2f руб.", $fam_1, $zarp_1);

echo "
";

printf("%".-12s%".10.2f руб.", $fam_2, $zarp_2);

echo "
";

?>

В качестве заполнителя была выбрана точка (‘. ) . Фамилии выравниваются по левому краю (- ) в поле шириной12 символов. Числа представляются в форме с фиксированной запятой в поле шириной10 символов и с точностью2 знака после запятой, с выравниванием по правому краю.