Могу ли я использовать htmlentities () в запросе SQL? - PullRequest
3 голосов
/ 04 февраля 2012

Большое спасибо за обсуждение, сгенерированный мой оригинальный вопрос. Я принял предложение Джея использовать bind_param (), но есть кое-что, что я не понимаю в этом, что может дать мне ошибку сервера: «Веб-сайт обнаружил ошибку при получении ...». Я не знаю, что означает параметр «sssd», поставляемый с примером.

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

<?php

$mysqli = new mysqli('my-database-address', 'my-username', 'my-password', 'my-database-name');
f (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit(); }

$stmt = $mysqli->prepare("INSERT INTO volunteers VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->bind_param('sssd', $first_name, $last_name, $street_address, $apt_unit, $city, $zip, 
$email, $phone, $planning, $signatures, $canvassing, $phone_bank, $media, $press_releases,
$volunteer_coordinator, $speaker, $house_parties, $web_page, $other, $skills, $organizations);

$first_name = '$_POST[first_name]'; $last_name = '$_POST[last_name]'; $street_address = '$_POST[street_address]';
$apt_unit = '$_POST[apt_unit]'; $city = '$_POST[city]'; $zip = '$_POST[zip]'; $email = '$_POST[email]';
$phone = '$_POST[phone]'; $planning = '$_POST[planning]'; $signatures = '$_POST[signatures]'; 
$canvassing = '$_POST[canvassing]'; $phone_bank = '$_POST[phone_bank]'; $media = '$_POST[media]'; 
$press_releases = '$_POST[press_releases]'; $volunteer_coordinator = '$_POST[volunteer_coordinator]'; 
$speaker = '$_POST[speaker]'; $house_parties = '$_POST[house_parties]'; $web_page = '$_POST[web_page]'; 
$other = '$_POST[other]'; $skills = '$_POST[skills]'; $organizations = '$_POST[organizations]';

$stmt->execute();
$stmt->close();

echo "<br /><br />";
echo "<div class='center-col-wrap'>";
echo "Your information has been received.";
echo "<br /><br />";
echo "Thank you for volunteering!"; echo "<br />";
echo "Your help in this effort to bring greater democracy to Oakland"; echo "<br />";
echo "will go a long way to create a healthy and informed community."; echo "<br />";
echo "<br /><br />";
echo "<a href='http://communitydemocracyproject.org/'>Return to CDP Home Page.</a>";
echo "</div>";

$mysqli->close();
?>

МОЙ ОРИГИНАЛЬНЫЙ ВОПРОС НИЖЕ:

Я не знал, сработает ли это или нет. Это не так Как я могу использовать htmlentities() здесь?

Любая помощь очень ценится.

$sql="INSERT INTO volunteers (first_name, last_name, street_address, apt_unit, city, zip, email, phone,
planning, signatures, canvassing, phone_bank, media, press_releases, volunteer_coordinator, speaker, 
house_parties, web_page, other, skills, organizations)
VALUES
('htmlentities($_POST[first_name])','htmlentities($_POST[last_name])','htmlentities($_POST[street_address])',
'htmlentities($_POST[apt_unit])','htmlentities($_POST[city])','htmlentities($_POST[zip])',
'htmlentities($_POST[email])','htmlentities($_POST[phone])','$_POST[planning]','$_POST[signatures]','$_POST[canvassing]','$_POST[phone_bank]',
'$_POST[media]','$_POST[press_releases]','$_POST[volunteer_coordinator]','$_POST[speaker]',
'$_POST[house_parties]','$_POST[web_page]','$_POST[other]','htmlentities($_POST[skills])','htmlentities($_POST[organizations])')";

Ответы [ 3 ]

8 голосов
/ 04 февраля 2012

Вы никогда хотите использовать htmlentities() для данных, которые будут вставлены в базу данных!

НИКОГДА!

Использовать толькоэто когда вы выводите данные на веб-страницу .

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

5 голосов
/ 04 февраля 2012

Как сказал Теодор, никогда не используйте htmlentities() для "экранирования" чего-то, что вы хотите поместить в свою БД.

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

Подготовленные операторы действительно просты в использовании.

Если вы используете PDO для доступа к вашей базе данных, справку можно найти здесь .Как вы можете видеть, метод bindParam() используется для назначения любого значения заполнителю в запросе.

Если вы используете mysqli, вы можете найти документы здесь .Синтаксис bind_param() немного отличается, поскольку заполнители не имеют имен (порядок имеет значение), а первый аргумент - это строка, определяющая тип аргументов («s» для строки, «i» для целого числа и т. Д.).

Использование подготовленных утверждений имеет несколько положительных эффектов.Прежде всего, он автоматически маскирует данные, предоставляемые методом bindParam() / bind_param(), и является лучшим способом закрыть вектор атаки SQL и даже оптимизирует производительность ваших запросов, сохраняяплан выполнения в базе данных (это немного увеличивает накладные расходы, но если вы выполняете запрос дважды, он окупается вдвое).

PS: htmlentities() следует использовать только в том случае, если вы хотите отобразить некоторый HTML в виде необработанного текстадля ваших пользователей (например, списки кодов).

PPS: не используйте real_escape_string() для предотвращения внедрения SQL, поскольку это небезопасно ( supeskt.org )

Обновление

Прежде всего, для продолжения вы должны задать новый вопрос.Люди не читают вопросы, которые уже помечены как ответы, и открывая новые вопросы, вы даете добрым людям возможность получить вознаграждение.:)

Тем не менее, первый аргумент "sssd" сообщает поставщику базы данных, что вы передаете четыре аргумента, три типа string и четвертый типа double (в примере в документации три строки и одна двойнаясвязанный ("DEU", "Баварский", "F" и 11.2)).Здесь, очевидно, дело не в этом, вы фактически передаете (связываете) 21 значение.

В зависимости от типа столбцов в вашей таблице volunteers вам необходимо передать строку из 21 символа в качестве первогоаргумент.Существует четыре возможных символа, которые можно использовать для определения типа:

  • i для целых чисел
  • d для двойных (числа с плавающей запятой)
  • s для строки
  • b для логического значения

Все, что вам нужно сделать, это проверить, какие типы столбцов БД имеются.Вы увидите, что типы в базе данных имеют разные имена (например, varchar, float и т. Д.).Если вы поищите в Google эти имена, вы обнаружите, что они похожи на строковые, целые, двойные и логические.Таким образом, вы должны выбрать наилучший тип соответствия в зависимости от типа столбца (строка ≆ varchar, double ≆ float, строка ≆ tinytext, строка ≆ date / datetime и т. Д.), И вы должны убедиться, что значения (ваши переменные $ _POST)на самом деле соответствует типу, который вы определили.

Предполагая, что все ваши столбцы имеют тип, подобный тексту типа varchar, первый аргумент будет выглядеть как 'sssssssssssssssssssss' (21 раз s) или 'ssssssssssssssissssss', если столбец, который принимаетволонтер_координатор имеет тип int (только для примера).

После того, как вы сделали это, вы должны дважды проверить, является ли f (mysqli_connect_errno()) ошибкой, связанной с копированием и вставкой, или вы действительно пропустили i в своем коде (должно быть if (mysqli_connect_errno())).

Если вы проверили, что вы должны написать $_POST['xyz'] вместо '$_POST[xyz]', это действительно поможет вам (' отмечает начало / конец строкии xyz фактически является строкой здесь).

Если вы все еще сталкиваетесь с ошибками, включите более подробную информацию об ошибкахдобавив error_reporting(E_ALL); вверху вашего файла (вы должны удалить его из соображений безопасности, когда ваш сайт запускается) и задать новый вопрос.

Обновление 2

ДелатьПроверьте строку подключения MySQL (аргументы, которые вы передаете в методе mysql()). Вы уверены, что ваш пароль начинается с @ и заканчивается полной остановкой? Кстати, вы не должны публиковать пароли и т. Д. В общественных местах.

Убедитесь, что ваш сервер поддерживает методы mysqli, запустив скрипт, содержащий только

<?php
// Show all information, defaults to INFO_ALL
phpinfo();
?>

и проверьте вывод на что-то вроде этого: MySQLi enabled

1 голос
/ 04 февраля 2012

Чтобы ответить на ваш вопрос именно так, как вы хотели, вам нужно выйти из вашей строки:

$sql="INSERT INTO volunteers (...) VALUES    
('".htmlentities($_POST['first_name'])."','".htmlentities($_POST['last_name'])'." ...

(Но, пожалуйста, как ясно говорит Теодор, не делайте этого. Это плохо.Действительно, не делайте этого. Пожалуйста!)

Я думаю, что вы пытаетесь избежать вашего ввода / вывода.Лучший способ сделать это, во-первых, остановить SQL-инъекцию, используя ваш любимый метод экранирования БД.Я просто использую это в качестве примера, у вас может быть лучшая настройка, чем у этого короткого примера кода:

$sql="INSERT INTO volunteers (...) VALUES    
('".$mysqli->real_escape_string($_POST['first_name'])."','".$mysqli->real_escape_string($_POST['last_name'])'." ...

А затем, когда вы выводите, выходите, используя htmlentities:

echo htmlentities($output->first_name);
...