Функції перевірки та очищення (за типами даних)

Небезпечні дані можуть прийти з різних джерел: юзери, інші веб-сайти, ваша база даних і т.д. Такі дані повинні перевірятися/очищатися (проходити валідацію) при отриманні або виведенні на екран. Наприклад, очищення потрібне при створенні SQL запиту. Новачки часто недооцінюють цю «не обов’язкову» процедуру – адже все ж таки і так працює.

WordPress пропонує купу функцій, щоб грамотно перевірити та очистити дані. У цій статті я зібрав всі функції валідації – для якого типу даних які функції PHP можна використовувати.

Багато функцій очищення даних підходять і для очищення даних, що приймаються.

Читайте також про принципи очищення даних


Функції валідації (за типами даних)


Числа

(int) $int
intval( $int )
Перетворює
$int на ціле число. Це функції PHP.
(float) $int
floatval( $int )
Перетворює
$int дробове число (число з плаваючою точкою). Це функція PHP.
absint( $int )
Перетворює
$int на ціле позитивне число. Тобто. якщо передати -5 поверне 5.


Масиви

array_map( ‘absint’, $array )

Перетворює всі значення $array на невід’ємні числа. array_map() – це PHP функція.

‘absint’ — це функція absint(), яка застосовується до значення масиву $array . Замініть ‘absint’ на будь-яку іншу назву функції та всі значення масиву будуть оброблені цією функцією.

map_deep( $value, $callback )
(з версії 4.4)
Застосовує зазначену функцію до значень переданого масиву або властивостей об’єкта. Рекурсивна функція.


Рядки (виведення на екран)

esc_html( $text )
Замінює спецсимволи на HTML сутності переданому тексті, повертає відформатований текст. Замінюються такі символи:
", ', &, <, >.
esc_attr( $text )
Перетворює знаки
" ' < > &на html сутності. Не створює подвійного перетворення.
esc_textarea( $text )
Очищає текст/рядок для використання в html тезі textarea.
esc_url( $url, $protocols, $_context )
Очищає УРЛ для використання в тексті, змінює неправильні та видаляє небезпечні символи.
esc_sql($data)
Підготовляє рядок до використання у запиті SQL. Захищає від ін’єкцій SQL. Може приймати масив рядків для обробки.
esc_js( $text )
Готує рядок для використання JavaScript. Щоб уберегти від помилок: екранує лапки, змінює символи
" <> &на спецсимволи HTML і виправляє закінчення рядка.
esc_html__( $text, $domain )
Перекладає рядок, замінюючи в ньому спецсимволи на HTML сутності. Повертає текст, яким можна відображати HTML як HTML код.
esc_html_e( $text, $domain )
Перекладає (локалізує) рядок і очищає його для виведення на екран – замінює в ньому спецсимволи на HTML сутності.
esc_attr__( $text, $domain )
Перекладає вказаний рядок та обробляє його функцією
esc_attr() .
esc_attr_e( $text, $domain )
Виводить перекладений текст, очищений функцією
esc_attr() .

Повний список функцій esc.


Рядки (прийняті дані)

WordPress функції для очищення

У WordPress є ряд функцій, за допомогою яких можна очистити рядки, які приходять у вигляді даних. Майже всі такі функції починаються з префіксу sanitize_:

sanitize_key( $key )
Очищає рядок, щоб використовувати його як ключ. Ключі використовуються як різні внутрішні ID. Залишить лише:
a-z0-9_-.
sanitize_text_field( $text )
Очищає рядок, що передається з поля input (зазвичай при збереженні в базу даних) або при отриманні з БД. Видаляє багато залишаючи тільки текст: без HTML тегів, переносів рядків і т.д.
sanitize_textarea_field( $text )
Очищає рядок, що передається з поля textarea (при збереженні в базу даних) або при отриманні з БД. Видаляє всі HTML символи, табуляції, HTML сутності та ін. Залишає чистий текст. З WP версії 4.7.
sanitize_html_class( $text )
Підготовляє текст для використання його в HTML атрибуті class: видаляє всі невідповідні символи.
sanitize_title( $title )
Використовується для створення ярликів записів/рубрик.
sanitize_title_with_dashes( $title )
Очищає заголовок, замінюючи пробіли на (-).
sanitize_user( $username, $strict )
Очищає ім’я користувача (логін, username), видаляючи небезпечні символи.

$strict = true — отже, в іменах будуть доступні тільки:
[a-zA-Z0-9 _*.-] .
sanitize_file_name( $filename )
Очищає назву файлу, замінюючи пробіли на ‘_’ та видаляючи неприпустимі символи.
sanitize_mime_type( $mime_type )
Очищає рядок для використання його як тип MIME. Видаляє все окрім
-+*.a-zA-Z0-9/.
sanitize_term_field( $field, $value, $term_id, $taxonomy, $context )
Очищає значення терміна (рубрики) для використання у тексті.
sanitize_post_field( $field, $value, $post_id, $context )
Очищає вказане значення вказаного поля посту.
sanitize_option( $option, $value )
Очищає значення різних опцій залежно від типу опції.
PHP функції для перевірки
ctype_alnum( $text )

Перевірять, чи складається переданий рядок тільки з чисел та літер.

ctype_alnum( 'AbCd1zyZ9'); // true
ctype_alnum('foo!#$bar'); // false
ctype_alnum('foo bar'); // false
strlen($string)
mb_strlen( $string )
Для перевірки того, що рядок має очікувану кількість символів.
preg_match( $pattern, $subject, $match )

Перевірка підрядки у рядку за регулярним виразом (маскою).

// перевірка за символами: може бути лише 0-9.-
if ( preg_match( '/[^0-9.-]/', $data ) ) {
	wp_die( 'Неправильний формат');
}
strpos( $haystack, $needle )

Для перевірки щодо наявності підрядки в іншому рядку.

$mystring = 'abc';
$findme = 'a';
if( false !== strpos( $mystring, $findme ) ){
	echo 'a знайдена в abc';
}


Рядки (HTML)

wp_kses( $string, $allowed_html )

Чистить рядок, залишаючи в ньому лише зазначені/допустимі HTML теги, їх атрибути та значення атрибутів. Слід використовувати при виведенні тексту, де можуть бути небезпечні HTML теги.

Для зручного використання wp_kses() має обгортки. Наприклад, щоб не передавати масив допустимих тегів, а використовувати базовий з мінімальним набором допустимих html тегів можна використовувати:

wp_kses_post( $text ) — видалити неприпустимі для запису теги з огляду на права поточного користувача.

wp_kses_post() , тільки чекає екрановані дані.

wp_kses_data( $text ) — якщо потрібно обмежити допустимі теги до мінімуму, як це робиться у коментарях. Чекає не екранований текст.

wp_filter_kses( $text ) – теж що і wp_kses_data() , тільки чекає екранований рядок.

wp_filter_nohtml_kses( $text ) – видаляє всі HTML теги з переданого тексту. Чекає на екранований рядок. Повертає чистий текст.

Фільтри wp_kses() повільні і з’їдають багато ресурсів, тому не варто використовувати їх щоразу при виведенні даних, краще очищати ними вхідні дані, наприклад, перед записом тексту в базу даних. Таке очищення, наприклад, запускається WordPress при додаванні коментаря або запису.

wp_rel_nofollow( $html )
Додає
rel="nofollow"всіх елементів
<a>у переданому HTML тексті.
wp_kses_allowed_html( $context )
Повертає масив допустимих HTML елементів для цього контексту. Див. опис…
balanceTags( $html )
force_balance_tags( $html )
Закриває незакрити HTML теги, щоб висновок не викликав помилку.


balanceTags() спрацьовує тільки якщо включена спеціальна настройка в налаштуваннях сайту «WordPress повинен виправляти некоректний XHTML-код автоматично.». А ось
force_balance_tags() спрацьовує завжди!
tag_escape( $tag_name )
Очищає назву HTML тега. Видаляє всі символи, крім
a-zA-Z0-9_:. Перекладає рядок у нижній регістр.
sanitize_html_class( $class, $fallback )
Підготовляє текст для використання його в HTML атрибуті class: видаляє всі невідповідні символи. Видаляє все окрім
A-Za-z0-9_-. Якщо результат порожній, то
$fallback можна встановити значення за замовчуванням.
wp_strip_all_tags( $string, $remove_breaks )

Видаляє всі HTML теги з рядка. script та style видаляються разом із вмістом.

Різниця зі strip_tags() – теги <script> та <style> видаляються разом із вмістом. Наприклад:

strip_tags('<script>something</script>'); // something
wp_strip_all_tags( '<script>something</script>' ); // Порожньо ''
strip_tags()
Видаляє всі HTML теги з рядка.


Email

is_email( $email )
Перевіряє, чи є переданий рядок адресою e-mail. Поверне true чи false.
sanitize_email( $email )
Очищає e-mail: видаляє неприпустимі символи з e-mail адреси.


URL (посилання)

esc_url($url)

Очищає УРЛ для використання в тексті, змінює неправильні та видаляє небезпечні символи. Не пропускає URL, якщо в ньому вказаний протокол не з білого списку (http, https, ftp, ftps, mailto, news, irc, gopher, nntp, feed та telnet).

Використовуйте це очищення під час виведення будь-якого URL на екран (у тексті, атрибутах або деінде).

Також, ця функція кодує деякі спец. рекомендується використовувати при генерації рядків для (X)HTML або XML документів. Кодує амперсанд (&) та одинарні лапки в їх числові сутності (&, ‘).

sanitize_url( $url )
esc_url_raw( $url )

Очищає УРЛ для безпечного використання. На відміну від esc_url() не очищає для безпечного виведення на екран. Використовуйте, коли потрібно отримати НЕкодовану URL-адресу, наприклад: у запитах до БД, при редиректах, в HTTP запитах.

sanitize_url() – це аліас esc_url_raw().

urlencode( $url )

PHP функція, яка кодує URL-адресу, так що його можна використовувати як параметр запиту. Тобто. замінює всі можливі символи URL ( &, /, пробелі т.д.) з їхньої сутності. Щоб повернути таку URL-адресу в попередній стан, використовуйте urldecode() .

Ця функція використовується не для виведення URL на екран, а для використання URL десь у запиті, щоб PHP не міг інтерпретувати рядок як URL. Наприклад, якщо обробити http://example.com/one, то отримаємо http%3A%2F%2Fexample.com%2Fone— це вже не URL, а рядок із набором символів.

urlencode_deep( $array )
Обробляє всі елементи переданого масиву функцією
urlencode() .


XML

XML документи, на відміну HTML, розуміють лише деякі спецсимволи: &apos;, &amp;, &gt;, &lt;, &quot;. Тому для виведення тексту для XML документів WordPress має функцію:

ent2ncr( $text )
Конвертує рядкові сутності в їх числові значення:
&rsquo; станет &#8217;.


JavaScript

esc_js( $text )

Готує рядок для використання JavaScript. Корисна при використанні однорядкового JS коду (в HTML атрибутах, наприклад onclick='…'). Рядок повинен бути укладений в одинарні лапки.

Або ось такий приклад:

<script>
	var = '<?php echo esc_js($js); ?>';
</script>


Файлова система

validate_file( $filename, $allowed_files )

Використовується для захисту від атаки “вихід за межі каталогу” (directory traversal attacks). Або, коли потрібно перевірити, чи знаходиться файл у білому списку (параметр $allowed_files).

Повертає: 0 – якщо перевірку пройдено. І поверне число помилки (> 0), якщо помилка. Це нестандартний підхід, тож будьте уважні при написанні коду!

Для перевірки функції потрібно передавати лише абсолютні шляхи без ../або ./. Наприклад /etc/hosts, пройде перевірку, а ./hosts– не пройде.

Атака виходу за директорію виглядає приблизно так, відправляється такий запит: http://test.ru/?dir=../../Windows/system.iniі якщо сервер або код не захищений, можна отримати вміст файлу system.ini .
Такі атаки не часті, судячи з інформації з google і відносяться до середнього ступеня ризику. Але ігнорувати їх все ж таки не варто…


HTTP Headers (URL, редиректи)

Атаки з поділом відповідей HTTP (header splitting attacks) створюються за клієнта, а чи не сервера і тому їх дуже важко виловити. WordPress іноді додає дані відправляються користувачем в HTTP заголовок, але щоб уникнути такі атаки, заголовки, що передаються, перевіряються в білому списку і все небезпечне вирізається.

Для очищення потенційно небезпечних заголовків у WordPress передбачені дві функції редиректу:

wp_redirect($location, $status = 302)
Безпечний спосіб перенаправити користувача на будь-яку URL-адресу. Функція перевіряє, щоб підсумковий HTTP запит не містив небезпечних даних.
wp_safe_redirect( $location, $status = 302 )
Ще надійніший спосіб редиректу, при якому перенаправлення можливе лише на дозволені в білому списку хости.
wp_sanitize_redirect( $location )
Очищає вказану URL-адресу для використання при перенаправленні.

Коротко про атаки з розділенням відповідей HTTP

У ході цієї атаки, також званої CRLF-ін’єкцією, вразливий веб-сервер відповідає на спеціально сформований шкідливий запит відповіддю HTTP, який інтерпретується як дві окремі відповіді замість однієї. Це стає можливим у випадках, коли в заголовках HTTP-відповіді використовуються дані, введені користувачем без додаткових перевірок. Зломщик може спровокувати ситуацію, при якій браузер жертви атаки інтерпретує доданий заголовок як відповідь на другий запит, при цьому спеціально сформовані дані будуть відображені та, можливо, додані до кешу браузера.

Для реалізації поділу відповідей HTTP з використанням вразливого сервера зломщик виконує наступні дії:

  • Виявляє можливості для введення даних користувачем із можливістю додавання цих даних у заголовок HTTP.

  • Формує шкідливий рядок для завершення запиту від програми та додавання власного запиту з необхідними даними в заголовку.

  • Примушує жертву атаки на відправку двох запитів серверу. Перший запит містить спеціально сформовані шкідливі дані у складі заголовка HTTP, а другий – запит від програми, тому браузер жертви атаки інтерпретує розділену відповідь таким чином, що він вважається таким, що належить другому запиту.

Докладніше читайте тут .


База даних

$wpdb->prepare( $format, $value1, $value2, … )

Очищає запит: безпечно замінює заповнювачі (placeholder) у $format вказаними в $value1, $value2, … значеннями.
$format — це рядок на кшталт sprintf() , у якому можна вказати лише наступні заповнювачі: %s, %dі %f. Немає необхідності в лапках для рядків ( %s ). prepare() додасть лапки сам, тобто. foo=%sстане foo='значение'. Але якщо лапки є, нічого страшного, функція розуміє таку конструкцію.

Працює на основі wpdb::_real_escape( $string ) із попередньою обробкою форматування.

$wpdb->get_var( $wpdb->prepare(
  "SELECT деякий FROM table WHERE foo = %s and status = %d",
  $_GET['name'], // 'не ' безпечні рядок' (функція зробить очищення сама)
  $_GET['status'] // 'небезпечне число (функція зробить очищення сама)
)));
esc_sql( $sql )
Екранує рядок або масив рядків для використання у запиті SQL. Спирається на функцію
addslashes() .


$wpdb->prepare() краще, тому що виправляє деякі помилки форматування (лапки).

Працює на основі
wpdb::_real_escape($string) .
$wpdb->escape_by_ref( &$text )
Чи не повертає дані, т.к. вони передаються за посиланням. Дані очищаються “на льоту”.

Працює на основі
wpdb::_real_escape( $string )
$wpdb->esc_like( $text )

Підготовка рядка для використання в LIKE частині SQL запиту. Оброблений рядок має бути ще оброблений однією з функцій очищення!

$link = $wpdb->esc_like($link); // підготуємо рядок для LIKE аргументу
$link = esc_sql($link); // Очистимо змінну
$link = '%'. $link. '%'; // створимо повну змінну пошуку LIKE
/ / $ Link готова для використання в SQL запиті.
sanitize_sql_orderby( $orderby )
Перевіряє, чи можна використовувати переданий рядок в ORDER BY частини SQL запиту.
sanitize_title_for_query( $title )
Підготовляє рядок для використання її як ярлик (slug) у запиті SQL. Очищення від ін’єкцій проводиться окремо. Мається на увазі, що це назва чого-небудь: заголовка, імені файлу і т.д.


Функції не пов’язані з типом даних

Інші функції очищення, які не увійшли до попередніх списків, тому що підходять для різних типів даних.

isset($var)
Перевіряє, чи існує змінна.
empty( $var )
Перевіряє чи порожня змінна. Ігнорує помилки, якщо змінної немає.
in_array( $needle, $haystack, true )
Для перевірки, чи є вказаний елемент у вказаному масиві.
count($array)
Для перевірки кількості елементів у масиві.
sanitize_meta( $meta_key, $meta_value, $meta_type )

Очищує значення мату даних. Сама функція нічого не робить, а приміряє фільтр "sanitize_{$meta_type}_meta_{$meta_key}", через який різні цілі дані можна очистити по-різному.

Примітно, що ця функція використовується у всіх функціях при додаванні/оновленні метаданих WordPress: update_*_meta()або add_*_meta(). Тобто. використовувати її безпосередньо зазвичай немає сенсу, але використовувати хук який вона обробляє дуже зручно при оновленні будь-яких метаданих…

sanitize_term( $term, $taxonomy, $context )
Очищає всі поля елемента таксономії за допомогою
sanitize_term_field() .

Також дивіться всі функції ядра, що містять exists , validate або is_ :


Функція filter_var()

filter_var() – це дуже цікава для перевірки та очищення даних функція.

Перевіряє чи очищує значення вказаної змінної за вказаними параметрами.

Повертає

Відфільтровані дані або FALSE у разі невдалої перевірки фільтрації.

Використання

$ var = filter_var ($ var, $ filter, $ options);
$var
(різне) (обов’язковий)
Змінна, яку потрібно очистити, перевірити.
$filter
(число)

ID фільтра, який буде використовуватися для перевірки, очищення. Такі ID зберігаються у вигляді чисел у визначених константах PHP. Їхній повний список можна подивитися тут:

За умовчанням вказана константа FILTER_DEFAULT, означає, що ніякий фільтр не застосовується.
За замовчуванням: FILTER_DEFAULT

$options
(масив/константа)

Різні параметри чи прапори фільтрації. Константою або комбінацією констант через |(АБО). Або може бути масивом, який підтримує всього 2 ключі: array('options'=>..., 'flags'=>... ).

Усі можливі прапори дивіться тут: прапори, які використовуються a filter_var .

Приклад опцій фільтрації, із зазначенням констант:

// повернути null за невдалої перевірки
filter_var('example.com', FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE ); //> null

// або прапори можна вказати в елементі масиву flags
filter_var('example.com', FILTER_VALIDATE_URL, array('flags'=>FILTER_NULL_ON_FAILURE) ); //> null

Приклад опцій фільтрації із зазначенням масиву:

// масив параметрів фільтрації
$options = array(
	'options' => array(
		'default' => 'http://example.com/info', // повернеться під час невдалої перевірки
	),
	'flags' => FILTER_FLAG_PATH_REQUIRED, // прапор: Включає зміст шляху в URL як необхідну умову.
);
$var = filter_var('http://example.com', FILTER_VALIDATE_URL, $options);

echo $var; //> http://example.com/info
// тобто. повернулося вказане значення за умовчанням,
// тому що прапор каже, що URL повинен бути шлях

Типово: null


Приклади filter_var()

#1 Демонстрація роботи

// email
$email = filter_var('[email protected]', FILTER_VALIDATE_EMAIL); //> [email protected]
$email = filter_var('bob@example', FILTER_VALIDATE_EMAIL); //> false

// url
$url = filter_var('http://example.com', FILTER_VALIDATE_URL); //> http://example.com
$url = filter_var('example.com', FILTER_VALIDATE_URL); //> false

$url = filter_var('http://example.com/path', FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED); //> http://example.com/path
$url = filter_var('http://example.com', FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED); //> false

#2 Перевіримо, чи є рядок IP адресою

if( filter_var( 'foo', FILTER_VALIDATE_IP ) )
	echo 'це IP';
else
	echo 'це не IP';

// виведе: 'це не IP'

if( filter_var( '123.111.222.123', FILTER_VALIDATE_IP ) )
	echo 'це IP';
else
	echo 'це не IP';

// виведе: 'це IP'

// Інакше можна записати так
filter_var( 'foo', FILTER_VALIDATE_IP ); //> false
filter_var( '123.111.222.123', FILTER_VALIDATE_IP ); //> true


Ваші функції валідації даних

Можна написати власні PHP функції і включити їх у тему або плагін.

При написанні функції перевірки, рекомендується назвати функції запитально, наприклад: is_phone() , is_available() , is_us_zipcode() .

Наприкінці функції завжди повертайте лише trueабо false!

Приклад 1

Приклад функції PHP, яка перевіряє, чи є значення індексом, що діє в США (за межами США, це називається поштовий код).

function is_us_zipcode( $zipcode ) {

	if ( empty( $zipcode ) ) {
		return false;
	}

	// a zip code should never have more than 10 characters
	if ( 10 <= strlen( trim( $content ) ) ) {

		// use a regex to check whether this zip code is correct
		if ( preg_match( '/^d{5}(-?d{4})?$/', $content ) ) {
			return true;
		}

	} else {
		return false;
	}
}

Тепер при отриманні даних поле можна перевірити так:

if( isset($_POST['wporg_zip_code']) && is_us_zip_code($_POST['wporg_zip_code']) ){
	// поле перевірено, робимо щось
}

Приклад 2

Допустимо ви збираєтеся створити запит для отримання записів, а користувачам потрібно дати можливість вибрати поле, за яким буде проходити сортування.

Цей приклад перевіряє вхідне поле сортування, вказане в input полі orderby . Варіантів можливих полів сортування та їх можна перерахувати – це буде наш білий список для перевірки. Перевіряти цей список за допомогою php функції in_array() .

<?php
$allowed_keys = ['author', 'post_author', 'date', 'post_date'];

// білий список у нижньому регістрі (author),
// тому змінимо дані, якщо вони вказані у верхньому регістрі (AUTHOR)
$orderby = strtolower( $_POST['orderby'] );

if( in_array( $orderby, $allowed_keys, true ) ){
	// перевірка пройдена змінюємо запит
}

Така перевірка за білим списком виключає будь-які інші значення, крім дозволених – це одна з найнадійніших перевірок і якщо можна зробити таку перевірку, робіть її обов’язково.

У третьому параметрі in_array() ми вказали true – це означає, що тип даних теж повинен збігатися – має бути рядок. Наприклад, якщо вказати в $_POST['orderby'] = true, а підробити запит так можна, і не вказати перевірку на кшталт, то перевірка буде пройдена завжди і ми отримаємо доступ до коду всередині перевірки:

// приклад поганої перевірки
if( in_array( true, [ 'date', 'author' ] ) )){
	// Цей код спрацьовуватиме завжди!
}

Інформація цього посібника взята з офіційного джерела та особистого досвіду.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *