Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP. Практика создания Web-сайтов (второе издание). Авторы: Кузнецов М.В., Симдянов И.В. PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум MySQL

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Запись в MySQL данных типа SET из HTML Select Multiple
 
 автор: danga   (23.10.2013 в 11:33)   письмо автору
 
 

Здравствуйте, продолжаю мучаться с HTML Select Multiple:)
Есть форма, которую пользователь заполняет на сайте, в ней он выбирает страны , куда хочет поехать. Надо эти страны записать в MySQL и потом сделать выбор по критерию "hostcountry" по всем пользователям.
Я пытаюсь в MySQL записать страны в поле с типом SET, но у меня не получается.
Саму базу я создаю в MySQL, а структуру таблицы в базе делаю через phpMyAdmin.

<html>
<head>
<title>Страница управления</title>
</head>
<body>
<form method='post' action='insert.php'>
Host countries:
<select multiple="" name="hostcountry[]" size="4">
<option value="1"> Australia </option>
<option value="2"> Austria </option>
<option value="3"> Belgium </option>
<option value="4"> Canada </option> 
<option value="5"> Denmark </option> 
<option value="6"> Finland </option>
<option value="7"> France </option>
<option value="8"> Germany </option>
<option value="9"> Ireland </option>
<option value="10"> Netherlands</option> 
</select>
<input type='submit' value='Добавить запись' />
</body>
</html>


PHP скрипт для внесения данных в таблицу я написала такой, но он не работает

<?php
include ('connect.php');
$hostcountry $_POST["hostcountry"]; 
foreach (
$_POST["hostcountry"] as $keys=>$values) echo "hostcountry:"$values"<br>"; .//это  для отладки, работает
foreach ($_POST["hostcountry"] as $keys=>$values$sql ='INSERT INTO members(hostcountry) $values'// это не работает
if(!mysql_query($sql))
{echo 
'<center><p><b>Ошибка при добавлении данных!</b></p></center>';}// это и выдается 
else 
{echo 
'<center><p><b>Данные добавлены!</b></p></center>';}
?>

Соединение с базой в скрипте 'connect.php' работает.
Кажется, распростаннная задача записать данные в тип SET, но почему-то нигде не могу найти, как это сделать. Может быть кто-то поможет?
С уважением
danga

  Ответить  
 
 автор: Igorek   (23.10.2013 в 14:04)   письмо автору
 
   для: danga   (23.10.2013 в 11:33)
 

Попробуйте так:

<?php
$hostcountry 
array_map('trim'$_POST["hostcountry"]);
// это для отладки
print "<pre>"
print_r($hostcountry); 
print 
"</pre>";

// это не для отладки
$values mysql_real_escape_string(implode(','$hostcountry));
$sql "INSERT INTO members(hostcountry) VALUES('$values')";

// это для отладки
echo $sql '<br>';

Данные для записи в тип SET должны быть перечислены через запятую как одно значение http://dev.mysql.com/doc/refman/5.0/en/set.html + вспоминаем правильный синтаксис команды INSERT

  Ответить  
 
 автор: Sfinks   (23.10.2013 в 19:16)   письмо автору
 
   для: danga   (23.10.2013 в 11:33)
 

А вам точно тип SET подходит?
Он не может содержать более 64 вариантов значений.
Стран, на сколько я знаю, несколько больше.....

  Ответить  
 
 автор: danga   (23.10.2013 в 20:01)   письмо автору
 
   для: Sfinks   (23.10.2013 в 19:16)
 

Да, вот именно. А какой может быть другой вариант? Я уже думала сделать отдельную таблицу для стран, в которой каждый столбец-новая страна. Но тогда столбцов будет очень много.

  Ответить  
 
 автор: confirm   (24.10.2013 в 10:16)   письмо автору
 
   для: danga   (23.10.2013 в 20:01)
 

Не столбец, а строка. А столбцы, это идентификатор, имя и прочие параметры страны.

  Ответить  
 
 автор: Sfinks   (25.10.2013 в 07:55)   письмо автору
 
   для: danga   (23.10.2013 в 20:01)
 

Это решается использованием 3х таблиц вместо одной.
Таблица 1 - пользователи (id, name, login, pass, и т.д.)
Таблица 2 - страны (id, name)
Таблица 3 - связь пользователя со странами (user_id, country_id). И каждая строка этой таблицы - Связь одного пользователя с одной страной:
user_id | country_id
--------------------
   1    |    10
   1    |    15
   1    |    164
   2    |    34
   2    |    12
   3    |    10
   4    |    252
   4    |    11

  Ответить  
 
 автор: danga   (25.10.2013 в 19:22)   письмо автору
 
   для: Sfinks   (25.10.2013 в 07:55)
 

Спасибо! Это проще и понятнее, чем с типом SET.

  Ответить  
 
 автор: danga   (27.10.2013 в 13:19)   письмо автору
 
   для: danga   (25.10.2013 в 19:22)
 

Здравствуйте.
Спасибо большое еще раз за совет, но я наверное такая бестолковая, что все равно не могу решить задачу до конца. В таблице 3 у меня никак не получается сделать несколько строк для одного пользователя.В лучшем случае получается только одна строка по последнему выбранному значению. Я пыталась сделать несколькими способами, и через цикл и с использованием ON DUPLICATE KEY UPDATE в разных комбинациях, наконец все собрала в одном скрипте - эффект тот же.
Вот этот вариант - выдает в таблицу только одно последнее из выбранных значений.

$hostcountry[] = $_POST["hostcountry"]; 
foreach ($_POST["hostcountry"] as $keys=>$values) {
$sql = 'INSERT INTO hostcountries(name, idcountry) 
VALUES("'.$name.'", "'.$values."') ON DUPLICATE KEY UPDATE idcountry=idcountry+1';

А этот вообще выдает ошибку.

$hostcountry = array_map('trim', $_POST["hostcountry"]);
$sql = 'INSERT INTO hostcountries(name, idcountry) 
VALUES("'.$name.'", '.$values.')
ON DUPLICATE KEY UPDATE idcountry=idcountry+1';

А уж как прилепить в эту таблицу user_id из первой таблицы внутри одной операции ввода - это вообще для меня загадка. Мне надо это динамическую форму регистрации добавить на готовый и работающий статический сайт. Помогите пожалуйста.

  Ответить  
 
 автор: Sfinks   (27.10.2013 в 13:44)   письмо автору
 
   для: danga   (27.10.2013 в 13:19)
 

У вас похоже не правильная структура таблицы.

Выполните и покажите результат запроса:
SHOW CREATE TABLE hostcountries

Тоже самое по двум остальным таблицам.

Плюс покажите саму HTML форму и ее пхп-обработчик.

Тогда можно будет что-то сказать.

> А уж как прилепить в эту таблицу user_id из первой таблицы внутри одной операции ввода - это
> вообще для меня загадка. Мне надо это динамическую форму регистрации добавить на готовый
> и работающий статический сайт. Помогите пожалуйста.

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

  Ответить  
 
 автор: danga   (27.10.2013 в 18:51)   письмо автору
 
   для: Sfinks   (27.10.2013 в 13:44)
 

Изначально я сделала сайт статический ( полностью html), но в нем есть форма регистрации, которую мне пользователи присылают на е-майл. А теперь я хочу сделать, чтобы пользовательские анкеты с фотографиями записывалось в базу, и потом пользователи могли бы выбирать из нее анкеты по критериям и редактировать и удалять свои собственные анкеты. Это вообще мой первый и единственный пока сайт:)))

  Ответить  
 
 автор: danga   (27.10.2013 в 19:08)   письмо автору
 
   для: danga   (27.10.2013 в 18:51)
 

Это конечно не вся анкета, а тест для отладки. Мне осталось научиться записывать и выводить потом из базы фотографии и массивы Select Multiple, все остальное у меня уже получаестя.
Вот такая тестовая HTML форма


<html>
<head>
 <title>Страница управления</title>
</head>
<body>
<form enctype="multipart/form-data" method='post' action='insert.php'>
Name: <input type='text' size='30' name='name'><br>
Famale: <input type='text' size='30' name='surname'><br>
E-mail: <input type='text' size=30 name='email'><br>
Gender:
<input type = "radio" name = "gender" value = "m"> male 
<input type = "radio" name = "gender" value = "f" checked> female
<br>
Host countries:
<select multiple="" name="hostcountry[]" size="4">
<option value="1"> Australia </option>
<option value="2"> Austria </option>
<option value="3"> Belgium </option>
<option value="4"> Canada </option> 
<option value="5"> Denmark </option> 
<option value="6"> Finland </option>
<option value="7"> France </option>
<option value="8"> Germany </option>
<option value="9"> Ireland </option>
<option value="10"> Netherlands</option> 
</select>
<br>
Add photo:<br>
<input type="file" name="photo" multiple accept="image/*,image/jpeg">
<br>
<input type='submit' value='Submit' />
</body>
</html>

  Ответить  
 
 автор: danga   (27.10.2013 в 20:33)   письмо автору
 
   для: danga   (27.10.2013 в 19:08)
 

Проверки на корректоность ввода делаются скриптами JavaScript И PHP, там все нормально. Осталось записать в базу MySQL все до конца.
Для отладки я закачала Apache2.2, MySQL Server5.1, PHP и phpMyAdmin. Базу данных test я сделала в MySQL, а таблицы в phpMyAdmin.

Сейчас у меня 4 таблицы:
1. members
Column Type Collation Attributes Null Default Extra
idaupair int(11) UNSIGNED No None AUTO_INCREMENT
name varchar(30) cp1251_general_ci No None
surname varchar(30) cp1251_general_ci No None
email varchar(30) cp1251_general_ci No None
gender enum('m', 'f') cp1251_general_ci No None
hosrcountry set('1','2','3','4','5','6','7','8','9','10') Yes None

2.hostcountries
idaupair int(11) UNSIGNED No None AUTO_INCREMENT
name varchar(30) cp1251_general_ci No None
idcountry int(3) No None

3. countries
idcountry int(3) UNSIGNED No None AUTO_INCREMENT
country varchar(30) cp1251_general_ci No None

4. photos
idaupair int(11) UNSIGNED No None AUTO_INCREMENT
photo blob BINARY No None
name varchar(30) cp1251_general_ci No None

  Ответить  
 
 автор: danga   (27.10.2013 в 20:53)   письмо автору
 
   для: danga   (27.10.2013 в 20:33)
 

В таблице members столбец hostcountry с типом SET отключен, потому что я не знаю как туда записать массив и сейчас пытаюсь эти данные записать в другую таблицу - hostcountries. Но у меня тоже не получается записать туда несколько строк для одного человека.
Последний вариант скрипта такой, он выдает ошибку придобавлении данных:
<?php
include ('connect.php');
$name $_POST['name'];
$surname $_POST['surname'];
$email $_POST['email'];
$gender $_POST['gender'];
$sql 'INSERT INTO members(name, surname, email, gender, hostcountry) 
VALUES("'
.$name.'", "'.$surname.'","'.$email.'", "'.$gender.'", '.$values.')';

$hostcountry array_map('trim'$_POST["hostcountry"]);

for (
$i=0$i<count($hostcountry); $i++) {
$sql 'INSERT INTO hostcountries(name, idcountry) 
VALUES("'
.$name.'", "'.$values.'")';
}
if(!
mysql_query($sql))
{echo 
'<center><p><b>Ошибка при добавлении данных!</b></p></center>';} 
else 
{echo 
'<center><p><b>Данные добавлены!</b></p></center>';}
?>
<?php
]

  Ответить  
 
 автор: confirm   (27.10.2013 в 21:21)   письмо автору
 
   для: danga   (27.10.2013 в 20:53)
 

<?php
//обязательно экранировать нужно строковые данные
//перед занесением их в базу
$name = isset($_POST['name']) ? mysql_real_escape_string($_POST['name']) : null
$surname = isset($_POST['surname']) ? mysql_real_escape_string($_POST['surname']) : null
$email = isset($_POST['email']) ? mysql_real_escape_string($_POST['email']) : null
$gender = isset($_POST['gender']) ? mysql_real_escape_string($_POST['gender']) : null
//а значения списка числа, поэтому их можно приводить к типу integer
$hostcountry array_map('intval'$_POST["hostcountry"]);
//но помнится, что уже еж говорил об этом, о проверке
//и делать надо так:
$hostcountry array_diff(array_map('intval'$_POST["hostcountry"]), array(0));

//если все данные присутствуют
if($name && $surname && $email && $gender && $hostcountry) {
    
$sql 'INSERT INTO members (name, surname, email, gender, hostcountry)  
            VALUES("'
.$name.'", "'.$surname.'","'.$email.'", "'.$gender.'", '.$values.')'//что за $values ?

    //пишем в базу, и пока не запишем удачно это никаких запросов, так как читайте ниже
    
if(mysql_query($sql))  {

        
//второй запрос надо полагать как то связан с первым, то есть таблицы
        //members и hostcountries связаны
        //а значит эта связь должна быть указана во второй таблице 
        //и скорее всего она у вас (если только вы не забыли этого сделать)
        //по идентификатору пользователя, поле которого в таблице должно быть
        //первичным ключом с авто инкрементом
        //то есть перед занесением в базу данных о пользователе, мы этого
        //идентификатора еще не знаем, и только после успешной записи первого запроса
        //получаем этот идентификатор так:  
        
$id mysql_insert_id();
    
        
//вот теперь можно подготавливать второй запрос и делать его
        //но много-строчной записью, всего одним запросом к базе
        
$sql 'INSERT INTO hostcountries (name, idcountry) VALUES ';
        foreach(
$hostcountry as $v$sql .= '('.$id.',"'.$name.'",'.$v.'),';
        
//хотя значение $name в этой таблице совсем не нужно, обращаться к ней
        //вы будете при выборке из первой, а в ней есть имя
        //в этой же таблице нужно идентификатор пользователя и значения которые он выбрал
    
        //ну и завершающий запрос
        
echo mysql_query(rtrim($sql,',')) ? '<center><p><b>Данные добавлены!</b></p></center>' 
                                          
'<center><p><b>Ошибка при добавлении данных!</b></p></center>';   

    } else echo 
'<center><p><b>Ошибка при добавлении данных!</b></p></center>';
    
//вот так, иначе нет смысла в несвязанных таблицах
    //вы же потом из них ничего не получите
} else {
    
//ошибка, не заполнены данные, возвращаем форму для заполнения
}


Всегда форматируйте код свой, делая в нем отступы, если ваш редактор сам этого не умеет делать иначе очень сложно в нем разбираться будет и вам самой.

Применение устаревшего тега center осуждается, хотя небо конечно не рухнет, но выше у вас форма с полем выбора файла позволяющего делать выбор нескольких файлов одним полем (type=file multiple), а это возможно только в современных браузерах, и как-то не вяжется center с этим. )

  Ответить  
 
 автор: Sfinks   (28.10.2013 в 08:50)   письмо автору
 
   для: danga   (27.10.2013 в 20:33)
 

SHOW CREATE TABLE hostcountries
Должен выглядеть примерно так:
CREATE TABLE `hostcountries` (
 `idaupair` int(10) unsigned NOT NULL,
 `idcountry` int(3) unsigned NOT NULL,
 PRIMARY KEY (`idaupair`,`idcountry`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Тогда можно будет добавить несколько строк для одного пользователя.

В остальном confirm ответил, за исключением того, что вот это:
<?
        $sql 
'INSERT INTO hostcountries (name, idcountry) VALUES '
        foreach(
$hostcountry as $v$sql .= '('.$id.',"'.$name.'",'.$v.'),'
        echo 
mysql_query(rtrim($sql,',')) ? '<center><p><b>Данные добавлены!</b></p></center>'  
                                          
'<center><p><b>Ошибка при добавлении данных!</b></p></center>';
я бы записал так:
<?
  
if($hostcountry){
    
$sql "INSERT INTO hostcountries (idaupair, idcountry) VALUES ($id,".implode("),($id,"$hostcountry).")"
    echo 
mysql_query($sql) ? '<center><p><b>Данные добавлены!</b></p></center>'  
                           
'<center><p><b>Ошибка при добавлении данных!</b></p></center>';
  }
Не люблю циклы.

  Ответить  
 
 автор: danga   (29.10.2013 в 00:43)   письмо автору
 
   для: Sfinks   (28.10.2013 в 08:50)
 

Sfinks и Confirm! Спасибо большое за помощь! очень приятно, что есть добрые и умные люди, кто может помочь. Скрипт Confirma в исходном варианте не работает, хотя я добавила в таблицы ключ PRIMARY KEY по столбцу idaupair. Правда, я его добавила в две таблицы - и в members и в hostcountries. Может это не правильно? Читаю сейчас документацию по MySQL, но что-то я плохо воспринимаю. Нужна практика, за неделю эту науку не постичь... Ну ладно, буду дальше разбираться:)))

  Ответить  
 
 автор: confirm   (29.10.2013 в 06:52)   письмо автору
 
   для: danga   (29.10.2013 в 00:43)
 

Я вам не код дал, а ваше писанное исправил, хотя в вашем писанном явные ошибки, имеется ввиду ссылки на данные. Поэтому и не работает.
Из того что я написал, вам главное, это понять, что я вам уже не первый раз говорю:
1) необходима обязательная проверка данных приходящих извне;
2) экранирование или приведение к типу данных перед занесением их или при использовании их при обращении к базе.

Два этих важных пункта и выполняют первые пять строк кода, а заодно и проверяют пришли ли данные, хотя если вообще полностью, с применением условной записи (тернарного оператора), должно быть так:

<?
//для строковых значений
$var_1 = isset($_POST['var_1']) ? mysql_real_escape_string(trim($_POST['var_1'])) : null;
//для числовых значений
$var_2 = isset($_POST['var_2']) ? (int)$_POST['var_2'] : null;


Такая запись удобна тем, что возвращая форму пользователю при ошибках ввода, в поля ее можно вернуть уже введенные пользователем данные:

<input name=var_1 value="<?=htmlspecialchars($var_1)?>" />
<input name=var_2 value=<?=$var_2?> />


И обязательно обезопасить вывод при выводе строковых значений в браузер - htmlspecialchars(). И применяя такое у себя, вы должны знать, что такая вставка php-переменных в html-код, без конструкции echo, возможна только в том случае, если у вас разрешены короткие РНР теги. Если это не так, то разрешите/включите их, это очень удобно.

Все что выше, это элементарные правила, которые вы просто обязаны выполнять при работе с данными извне.

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

<?
//этот код вернет массив $_POST с обработанными указанным способом данными
//готовыми для дальнейшего использования их при работе с базой
array_walk_recursive($_POST, function(&$v) {
    
//здесь можно вообще произвести более сложные проверки входных данных,
    //как например, в зависимости от типа ожидаемых данных
    //сразу приводить их к этому типу  
    
$v mysql_real_escape_string(trim(stripslashes($v)));
});
//используя этот код, необходимо знать, что он будет работать только в версии РНР не ниже 5.3
//так как вместо вызова callback-функции используется замыкание 


PRIMARY KEY которое прописал Sfinks не определяет, что код который я написал, должен обязательно стать рабочим (еще раз говорю, это только исправление вами писанного так, как должно быть "по уму"), это просто применение ключа к полям таблицы, которые нужны для того, чтобы MySQL оптимальнее выполняла свои запросы. Кроме этого он пишет, но не объясняет, что лучше использовать implode(). Это так, легко превратить массив в строку, и даже не просто превратить, а сразу и обработать данные этого массива, например, тоже экранирование их и обрамление кавычками перед записью в базу:

<?
$string 
'"' implode('","'array_map('mysql_real_escape_string'$array)) . '"';


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

Если вы поняли уже, что такое связанные таблицы и как они связываются (на основе чего), то вся блок схема кода простая:

1. получить данные и проверить их
2. если все обязательные данные получены и они корректные, то запись в базу основных данных (первая таблица)
3. если основных данные записались в базу, то получить идентификатор записи в базу
4. подготовить данные для записи во вторую таблицу
5. записать данные во вторую таблицу связывая их с первой по полученному идентификатору
(здесь надо отметить, что "ждать идентификатор" от записи в первую таблицу, чтобы произвести запись во вторую, это не всегда обязательное условие записи данных в связанные таблицы, но в вашем случае, это именно обязательное условие)
а) в шаге 3 и 5, если произошла ошибка при записи в базу, то вывести сообщение
6. если в шаге 1 ошибка с данными от пользователя (не все получены, или введены некорректно), а также, если массив $_POST пуст (первое обращение к странице), то возвращаем форму пользователю

  Ответить  
 
 автор: Sfinks   (29.10.2013 в 10:10)   письмо автору
 
   для: confirm   (29.10.2013 в 06:52)
 

> Кроме этого он пишет, но не объясняет, что лучше использовать implode().
К сожалению, на такую развернутую лекцию у меня ушло бы минимум часа 2, а-то и 3. Поэтому да, мои ответы чаще всего несколько обрывочны. Спасибо, что дополняете =)

Для danga:
> хотя я добавила в таблицы ключ PRIMARY KEY по столбцу idaupair. Правда, я его добавила в две таблицы - и в members и в hostcountries
Вы не поняли.
В таблице members должен быть первичный ключ по ID мембера.
В таблице countries - по ID страны.
А в таблице соответствий hostcountries - должен быть составной первичный ключ, сразу по двум полям ID мембера и ID страны:
PRIMARY KEY (`idaupair`,`idcountry`)
Тогда можно будет для каждого ID мембера добавить несколько строк с разными ID страны.

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования