Вопрос или проблема
У меня есть пользовательский плагин для сайта на WordPress, который является онлайн-сообществом автомобилей на php5.6. Я не разрабатывал сайт изначально, но теперь я его куратор. У меня ограниченные знания в программировании. В моем плагине около 6 строк в различных местах, таких как эти:
$title = mysql_escape_string(stripslashes($_POST['title']));
$content = mysql_escape_string(stripslashes($_POST['article']));
return mysql_escape_string(stripslashes($_POST[$value]));
Мне нужно перейти на PHP7, но, конечно, это устаревший и устаревший метод взаимодействия с базой данных.
Я был бы рад помощи, чтобы предложить самый чистый и надежный способ заменить эту именно строку либо запросом wpdb, либо методом esq_sql. Я видел, что это упоминается во многих статьях, но не знаю правильного синтаксиса или вопросов безопасности, учитывая, что мои строки также содержат ‘stripslashes’.
Заранее спасибо.
Пример строк внутри функций моего плагина выглядит следующим образом:
function getPostValueOrNothing($value) {
if (isset($_POST[$value])) {
return mysql_escape_string(stripslashes($_POST[$value]));
} else {
return "";
}
}
и вы можете увидеть повторяющуюся зависимость от этого в следующем фрагменте:
<?php global $post;
$author_id = bp_displayed_user_id();
$user = get_user_by('id', $author_id);
if (is_user_logged_in() && $author_id == get_current_user_id() && isset($_POST['userpinfield'])) {
if ($_POST['userpinfield'] != "") {
echo "<p>Ошибка проверки</p>";
} else {
$post_id = -1;
$attach_id = -1;
$meta_key = "car_id";
$title = getPostValueOrNothing('title');
$content = $_POST['article'];
$year = getPostValueOrNothing('year');
$pdate = getPostValueOrNothing('pdate');
$reg = getPostValueOrNothing('reg');
$commNo = getPostValueOrNothing('commNo');
$engineNo = getPostValueOrNothing('engineNo');
$vin = getPostValueOrNothing('vin');
$colour = getPostValueOrNothing('colour');
$ccolour = getPostValueOrNothing('to_close_colour');
$mileage = getPostValueOrNothing('mileage');
$location = getPostValueOrNothing('location');
if (isset($_POST['post_id']) && $_POST['post_id'] == -1) {
if (null == get_page_by_title($title)) {
$slug = str_replace(" ", "-", strtolower($title));
} else {
$titleSlug = $title . "" . rand(1, 9);
while (null != get_page_by_title($title)) {
$titleSlug = $titleSlug . "" . rand(1, 9);
}
$slug = str_replace(" ", "-", strtolower($titleSlug));
}
//Создание поста
$post_id = wp_insert_post(
array(
'comment_status' => (!empty($_POST['comment_status']))? $_POST['comment_status'] : 'closed',
'ping_status' => 'closed',
'post_author' => $author_id,
'post_name' => $slug,
'post_title' => $title,
'post_content' => $content,
'post_status' => 'publish',
'post_type' => 'to_car'
)
);
//Создание Темы поста
$topic_id = wp_insert_post(
array(
'comment_status' => 'closed',
'ping_status' => 'closed',
'post_author' => $author_id,
'post_name' => $slug . 'topic',
'post_title' => $title,
'post_content' => $content,
'post_status' => 'publish',
'comment_stattus' => 'open',
'post_type' => 'topic'
)
);
add_post_meta($topic_id, $meta_key, $post_id);
add_post_meta($topic_id, '_bbp_forum_id', $topic_id);
add_post_meta($topic_id, '_bbp_topic_id', $topic_id);
add_post_meta($topic_id, '_bbp_last_active_time', date('Y-m-d H:m:s'));
add_post_meta($topic_id, '_bbp_author_ip', $_SERVER['REMOTE_ADDR']);
add_post_meta($post_id, 'topic_id', $topic_id);
add_post_meta($post_id, 'to_year', $year);
add_post_meta($post_id, 'to_vin', $vin);
add_post_meta($post_id, 'to_comm', $commNo);
add_post_meta($post_id, 'to_engine_no', $engineNo);
add_post_meta($post_id, 'to_reg', $reg);
add_post_meta($post_id, 'to_date', $pdate);
add_post_meta($post_id, 'to_mileage', $mileage);
add_post_meta($post_id, 'to_colour', $colour);
add_post_meta($post_id, 'to_close_colour', $ccolour);
add_post_meta($post_id, 'to_views', 0);
if (!function_exists('media_handle_upload')) {
require_once(ABSPATH . "wp-admin" . '/includes/image.php');
require_once(ABSPATH . "wp-admin" . '/includes/file.php');
require_once(ABSPATH . "wp-admin" . '/includes/media.php');
}
if ($_FILES) {
foreach ($_FILES as $file => $array) {
if ($_FILES['feature']['error'] !== UPLOAD_ERR_OK) {
if ($_FILES['feature']['error'] != 4) {
echo "ошибка загрузки : " . $_FILES['feature']['error'];
}
} else {
$attach_id = media_handle_upload('feature', $post_id);
}
}
}
if ($attach_id > 0) {
update_post_meta($post_id, '_thumbnail_id', $attach_id);
}
$terms = get_terms('to_make');
if ($terms) {
foreach ($terms as $term) {
$modelValue = getPostValueOrNothing('model' . $term->term_id);
if ($modelValue != "") {
update_post_meta($post_id, 'to_model', $modelValue);
break;
}
}
}
$post = get_post($post_id);
$dummyUrl = plugins_url('/imgs/noCar.png', __FILE__);
$html="<div><span>Добавлено новое Авто</span></div><div><a href="" . get_bloginfo('url') . '/to-car/' . $post->post_name . '">';
if (has_post_thumbnail()) {
$html .= '<img src="' . get_the_post_thumbnail_url(get_the_ID(), 'thumbnail') . '" title="' . get_the_title() . '" alt="' . get_the_title() . '" />';
}else{
$html .= '<img src="' . $dummyUrl . '" title="' . get_the_title() . '" alt="' . get_the_title() . '" />';
}
$html .= '<div><span>' . get_the_title() . '</span></div>';
$html .= '</a></div>';
bp_fmsu_generate_activity($author_id, $slug, $html);
echo "<p>Авто сохранено!</p>";
} else {
$post_id = mysqli_real_escape_string(stripslashes($_POST['post_id']));
if (is_nan($post_id)) {
echo "Не удается обновить объявление.";
} else {
$current_item = array(
'ID' => $post_id,
'post_title' => $title,
'post_content' => $content,
'comment_status' => (!empty($_POST['comment_status']))? $_POST['comment_status'] : 'closed',
);
wp_update_post($current_item, true);
if (is_wp_error($post_id)) {
$errors = $post_id->get_error_messages();
foreach ($errors as $error) {
echo $error;
}
} else {
update_post_meta($post_id, 'to_year', $year);
update_post_meta($post_id, 'to_vin', $vin);
update_post_meta($post_id, 'to_comm', $commNo);
update_post_meta($post_id, 'to_engine_no', $engineNo);
update_post_meta($post_id, 'to_reg', $reg);
update_post_meta($post_id, 'to_date', $pdate);
update_post_meta($post_id, 'to_mileage', $mileage);
update_post_meta($post_id, 'to_colour', $colour);
update_post_meta($post_id, 'to_close_colour', $ccolour);
update_post_meta($post_id, 'to_views', 0);
//Создание Темы поста
if (!function_exists('media_handle_upload')) {
require_once(ABSPATH . "wp-admin" . '/includes/image.php');
require_once(ABSPATH . "wp-admin" . '/includes/file.php');
require_once(ABSPATH . "wp-admin" . '/includes/media.php');
}
if ($_FILES) {
foreach ($_FILES as $file => $array) {
if ($_FILES['feature']['error'] !== UPLOAD_ERR_OK) {
if ($_FILES['feature']['error'] != 4) {
echo "ошибка загрузки : " . $_FILES['feature']['error'];
}
} else {
echo "файл загружен";
$attach_id = media_handle_upload('feature', $post_id);
}
}
}
if ($attach_id > 0) {
update_post_meta($post_id, '_thumbnail_id', $attach_id);
}
$post = get_post($post_id);
$dummyUrl = plugins_url('/imgs/noCar.png', __FILE__);
$html="<div><span>Обновлено Авто</span></div><div><a href="" . get_the_permalink() . '">';
if (has_post_thumbnail()) {
$html .= '<img src="' . get_the_post_thumbnail_url(get_the_ID(), 'thumbnail') . '" title="' . get_the_title() . '" alt="' . get_the_title() . '" />';
} else{
$html .= '<img src="' . $dummyUrl . '" title="' . get_the_title() . '" alt="' . get_the_title() . '" />';
}
$html .= '<div><span>' . get_the_title() . '</span></div>';
$html .= '</a></div>';
bp_fmsu_generate_activity($author_id, $slug, $html);
echo '<p class="ajaxmessage">Авто обновлено!</p>';
}
}
}
}
}
?>
Вам не нужно очищать переменные, которые передаются в wp_update_post()
, потому что wp_update_post()
после некоторых проверок передает данные в wp_insert_post()
, и wp_insert_post()
вызывает sanitize_post()
, который осуществляет очистку всех аргументов.
Также add_post_meta
и update_post_meta
также выполняют всю очистку для вас.
Чтобы ответить на ваш вопрос, я бы заменил mysql_escape_string
на $wpdb->esc_sql($_POST[$value])
. Это вызывает mysqli_real_escape_string
, если поддерживается, или mysql_real_escape_string
в противном случае.
НО всякий раз, когда вы выводите что-то внутри кода HTML, вы всегда должны экранировать значения, используя esc_html($value)
, esc_url($url)
, esc_attr($attribute)
и т. д.
Дополнительно: Проверка данных
Ответ или решение
Вас интересует замена устаревшей функции mysql_escape_string
в пользовательском плагине для WordPress при переходе на PHP 7.4. Вы правы в том, что использование этой функции не рекомендуется. Рекомендую использовать встроенные функции WordPress для обеспечения безопасности и надежности.
Замена mysql_escape_string
Сначала давайте проанализируем ваши строки кода, использующие mysql_escape_string
:
$title = mysql_escape_string(stripslashes($_POST['title']));
$content = mysql_escape_string(stripslashes($_POST['article']));
return mysql_escape_string(stripslashes($_POST[$value]));
Вместо использования mysql_escape_string
, вы можете использовать $wpdb->esc_sql()
вместе с безопасными методами для работы с данными из поста.
Использование $wpdb->esc_sql
Класс wpdb
в WordPress предоставляет метод esc_sql
, который автоматически экранирует строки перед их использованием в SQL-запросах. Однако важно понимать, что это не всегда замена для предварительной обработки данных. Мы можем обеспечить безопасность данных с помощью валидации и фильтрации перед их сохранением в базе данных.
Пример исправленного кода
Предлагаю переписать вашу функцию getPostValueOrNothing
так:
global $wpdb;
function getPostValueOrNothing($value) {
if (isset($_POST[$value])) {
return $wpdb->esc_sql(stripslashes($_POST[$value]));
} else {
return "";
}
}
Работа с постами и метаданными
В вашем коде вы также делаете вставку и обновление постов, где Данные, передаваемые в функции wp_insert_post
и wp_update_post
, проходят через встроенные механизмы валидации WordPress. Этот подход очень важен. Следует помнить, что вам не нужно дополнительно экранировать данные, передаваемые в эти функции. Они уже содержат защиту от SQL-инъекций.
Пример вставки поста:
$post_id = wp_insert_post(array(
'comment_status' => (!empty($_POST['comment_status'])) ? $_POST['comment_status'] : 'closed',
'ping_status' => 'closed',
'post_author' => $author_id,
'post_name' => $slug,
'post_title' => $title,
'post_content' => $content, // Безопасно, так как wp_insert_post заботится об экранировании
'post_status' => 'publish',
'post_type' => 'to_car'
));
Экранирование значений при выводе
При выводе данных на экран важно использовать функции экранирования, чтобы избежать XSS-уязвимостей. Используйте esc_html()
, esc_url()
, и esc_attr()
в зависимости от контекста. Например:
echo '<div>' . esc_html(get_the_title()) . '</div>';
Заключение
Переход на PHP 7 и работа с современными стандартами безопасности — отличный шаг в развитии вашего плагины. Используйте $wpdb->esc_sql()
для безопасного выполнения SQL-запросов, а встроенные функции WordPress для вставки и обновления данных. Не забудьте об экранировании значений при выводе на экран.
Эти изменения не только помогут избежать проблем с безопасностью, но и сделают ваш код более чистым и поддерживаемым.