wpdb::prepare() publicWP 2.3.0

Дозволяє писати SQL запит з очищенням параметрів, що передаються в нього.

У рядку запиту замість параметра, що передається, потрібно використовувати плейсхолдер:

  • %d(integer)
  • %f(float)
  • %s(string)

Також для кожного з плейсхолдерів вказується PHP змінна, яка замінить плейсхолдер. При заміні змінна буде очищена . Синтаксис схожий на sprintf() .

З WP 3.5 обов’язково повинні бути передані щонайменше 2 параметри: запит і значення змінної, інакше буде php помилка (User Notice).

Лапки для плейсхолдерів %sта '%s'.

Плейсхолдери можуть бути в лапках або без них: WHERE field = %sабо WHERE field = '%s'. Лапки прийнято не ставити.

echo $wpdb->prepare( "foo = %s", 'a'); // foo = 'a'
echo $wpdb->prepare( "foo = '%s'", 'a' ); // foo = 'a'
Параметр кожного плейсхолдера.

Параметр має бути вказаний для кожного плейсхолдера.

echo $wpdb->prepare( 'foo = %s AND bar = %s', 'a' );
echo $wpdb->prepare( 'foo = %1$s AND bar = %1$s', 'a' );
// В обох випадках побачимо помилку:
// User Notice: wpdb::prepare був названий incorrectly.
// The query does no contain the correct number of placeholders (2)
// for number of arguments passed (1).
Порядкові плейсхолдери %1$s.

Для сумісності зі старими версіями: порядкові плейсхолдери (наприклад, %1$s, %5s) обробляються інакше – їм не додаються лапки, тому вони мають бути забезпечені правильними лапками у рядку запиту.

echo $wpdb->prepare( 'foo = %1$s', 'a"a' ); // foo = a"a
echo $wpdb->prepare( 'foo = "%1$s"', 'a"a' ); // foo = "a"a"
echo $wpdb->prepare( 'foo = %1s', 'a"a' ); // foo = a"a
echo $wpdb->prepare( 'foo = %s', 'a"a' ); // foo = 'a"a'
Знак%

Знак %у рядку запиту, який не відноситься до плейсхолдеру, потрібно записувати так %%.

echo $wpdb->prepare( "%foo AND id = %d", 2 ); // User Notice: wpdb::prepare був названий incorrectly.
echo $wpdb->prepare( "%%foo AND id = %d", 2 ); // %foo AND id = 2
%у LIKE синтаксисі

Підстановочні знаки відсотка %в LIKE синтаксисі повинні вказуватися через параметр підстановки, що містить повний LIKE рядок, а не безпосередньо у запиті. Також дивіться wpdb::esc_like() .

$like = '%'. $wpdb->esc_like( "bar's" ) .'%end';
echo $wpdb->prepare( "foo LIKE %s", $like ); // foo LIKE '{a0d1d}bar's{a0d1d}end'

SQL ін’єкція

У SQL є таке поняття як ін’єкція (впровадження в запит SQL коду). Зробити його можна, коли на запит передаються динамічні дані. Наприклад, у запит передається значення input поля, це поле можна вказати дані, які у результаті стануть частиною SQL запиту. Так можна запропонувати запит і щось зіпсувати або просто порушити код самого запиту. Виглядає це так:

$sql = "SELECT * FROM table WHERE id = '$var'";

Тепер, якщо var = 2' AND id = (DROP TABLE table2)то в результаті запит вийти такий:

SELECT * FROM table WHERE id = '2' AND id = (DROP TABLE table2)

Таким чином, можна впровадитися в сам запит і змінити його. Щоб цього не відбулося запити з перемінними, що передаються в них, потрібно обробляти методом prepare() :

$sql = $wpdb->prepare( "SELECT * FROM table WHERE id = %s", $var);

esc_sql()

Крім методу $wpdb->prepare(), запит можна очистити функцією esc_sql() . Але «prepare» краще, тому що виправляє деякі помилки форматування.

$name = esc_sql($name);
$status = esc_sql($status);

$wpdb->get_var( "SELECT something FROM table WHERE foo = '$name' and status = '$status'" );

ВАЖЛИВО! Після esc_sql() очищений рядок можна використовувати тільки всередині лапок ''або "". Тобто. правильно писати field = '$value', а не field = $valueде$value = esc_sql( $value );

{} Це метод класу: wpdb{}

Працює на основі:
wpdb::add_placeholder_escape()

Хуків немає.

Повертає

Строку|null. Sanitized query string, якщо це є query to prepare.

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

Global $wpdb;
$wpdb->prepare( $query, ...$args );
$query
(рядок) (обов’язковий)

Рядок запиту. У ньому можна використовувати замінники:

  • %d– Число
  • %s– Рядок
  • %f– Дробове число (число з плаваючою точкою, з версії 3.3).
…$args
(рядок/число/масив)

Змінні, які будуть використані для заміни плейсхолдерів %s %d %fу рядку запиту.

Ці змінні можна вказати через кому (як додаткові параметри функції) або в масиві:

  • $wpdb->prepare( 'query', $param1, $param2 )
  • $wpdb->prepare( 'query', [ $param1, $param2 ] ).

Приклади

0

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

$wpdb->prepare(
	"SELECT * FROM `table` WHERE `column` = %s AND `field` = %d OR `other_field` LIKE %s",
	[ 'foo', 1337, '% bar']
);

$wpdb->prepare(
	"SELECT DATE_FORMAT(`field`, '%%c') FROM `table` WHERE `column` = %s", 'foo'
);
0

#2 Додамо довільне поле до поста 10

З прикладу видно, що з prepare() немає необхідності дбати про екранування лапок та інше, що може зашкодити запиту.

$metakey = " крах " БД " ;
$metavalue = "WordPress може 'зламати' Базу Даних якщо не екранувати запит.";

$wpdb->query(
	$wpdb->prepare(
		"INSERT INTO $wpdb->postmeta ( post_id, meta_key, meta_value ) VALUES ( %d, %s, %s )",
		10,
		$metakey,
		$metavalue
  )
);
0

#3 Передача параметрів у вигляді масиву

Це такий самий приклад, тільки тут всі змінні передаються у другому параметрі як масиву.

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

$metakey = " крах " БД " ;
$metavalue = "WordPress може 'зламати' Базу Даних якщо не екранувати запит.";

$wpdb->query(
	$wpdb->prepare(
		"INSERT INTO $wpdb->postmeta ( post_id, meta_key, meta_value ) VALUES ( %d, %s, %s )",
		array(
			10,
			$metakey,
			$metavalue
		)
  )
);

список змін

З версії 2.3.0Введено.
З версії 5.3.0Formalizated existing and already documented …$args parameter by updating the function signature. The second parameter був змінений від $args to …$args .

wpdb::prepare WP 6.0.2

public function prepare( $query, ...$args ) {
	if ( is_null( $query ) ) {
		return;
	}

	// Це не означає, що не буде боротьбою - але це буде catch obviously incorrect usage.
	if ( strpos( $query, '%' ) === false ) {
		wp_load_translations_early();
		_doing_it_wrong(
			'wpdb::prepare',
			sprintf(
				/* translators: %s: wpdb::prepare() */
				__( 'The query argument of %s must have a placeholder.' ),
				'wpdb::prepare()'
			),
			'3.9.0'
		);
	}

	// Якщо args були passed as array (as in vsprintf), movem them up.
	$passed_as_array = false;
	if ( isset( $args[0] ) && is_array( $args[0] ) && 1 === count( $args ) ) {
		$passed_as_array = true;
		$args = $args[0];
	}

	foreach ( $args as $arg ) {
		if ( ! is_scalar( $arg ) && ! is_null( $arg ) ) {
			wp_load_translations_early();
			_doing_it_wrong(
				'wpdb::prepare',
				sprintf(
					/* translators: %s: Value type. */
					__( 'Unsupported value type (%s).' ),
					gettype( $arg )
				),
				'4.8.2'
			);
		}
	}

	/*
	 * Специфікація формування займається в зоні місця перебування. The following are allowed:
	 *
	 * - Sign specifier. eg, $+d
	 * - Numbered placeholders. eg, %1$s
	 * - Padding specifier, включаючи custom padding characters. eg, %05s, %'#5s
	 * - Alignment specifier. eg, %05-s
	 * - Precision specifier. eg, %.2f
	 */
	$allowed_format = '(?:[1-9][0-9]*[$])?[-+0-9]*(?: |0|'.)?[-+0-9]* (?: . [0-9] +)?';

	/*
	 * Якщо %s placeholder already has quotes around it, removing the existing quotes and re-inserting them
	 * ensures the quotes are consistent.
	 *
	 * Для backward compatibility, це є тільки applied to %s, і не placeholders як %1$s, які є frequently
	 * Використовується в середині longer strings, або як table name placeholders.
	 */
	$query = str_replace( "%s", %s, $query ); // Strip any existing single quotes.
	$query = str_replace( '%s', '%s', $query ); // Strip any existing double quotes.
	$query = preg_replace( '/(?<!%)%s/', "'%s'", $query ); // Quote the strings, avoiding escaped strings як %%s.

	$query = preg_replace( "/(?<!%)(%($allowed_format)?f)/", '%2F', $query ); // Force floats to be locale-unaware.

	$query = preg_replace( "/%(?:%|$|(?!($allowed_format)?[sdF])))/", '%%1', $query ); // Escape any unescaped percents.

	// Count the number of valid placeholders in the query.
	$placeholders = preg_match_all( "/(^|[^%]|(%%)+)%($allowed_format)?[sdF]/", $query, $matches );

	$ args_count = count ($ args);

	if ( $args_count !== $placeholders ) {
		if ( 1 === $placeholders && $passed_as_array ) {
			// Якщо passed query тільки expected один argument, але wrong number of arguments були sent as array, bail.
			wp_load_translations_early();
			_doing_it_wrong(
				'wpdb::prepare',
				__( 'The query only expected one placeholder, but array of multiple placeholders was sent.' ),
				'4.9.0'
			);

			return;
		} else {
			/*
			 * Якщо ми не повинні мати правий номер placeholders, але вони були прописані як окремі argumenty,
			 * або ми були expecting multiple arguments in array, throw a warning.
			 */
			wp_load_translations_early();
			_doing_it_wrong(
				'wpdb::prepare',
				sprintf(
					/* translators: 1: Number of placeholders, 2: Number of arguments passed. */
					__( 'The query does no contain the correct number of placeholders (%1$d) for the number of arguments passed (%2$d).' ),
					$placeholders,
					$args_count
				),
				'4.8.3'
			);

			/*
			 * Якщо ми не маємо багато arguments до матчу placeholders,
			 * return empty string to avoid fatal error на PHP 8.
			 */
			if ( $args_count < $placeholders ) {
				$max_numbered_placeholder =! empty( $matches[3] ) ? max( array_map( 'intval', $matches[3] ) ) : 0;

				if ( ! $max_numbered_placeholder || $args_count < $max_numbered_placeholder ) {
					return '';
				}
			}
		}
	}

	array_walk( $args, array( $this, 'escape_by_ref' ) );
	$query = vsprintf($query, $args);

	return $this->add_placeholder_escape( $query );
}

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

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