Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.73/15: Рейтинг темы: голосов - 15, средняя оценка - 4.73
142 / 16 / 2
Регистрация: 21.01.2013
Сообщений: 54

Запись кириллицы в БД CGI-скриптом на C++

12.06.2017, 21:58. Показов 3154. Ответов 13

Студворк — интернет-сервис помощи студентам
Задача такая: CGI-скрипт расположенный на сайте получает через GET параметры на русском языке. Далее он должен эти значения добавить в таблицу БД MySQL сайта.
Целевая ячейка в таблице БД имеет тип varchar(64) и кодировку utf8_general_ci (можно поставить другую, это не критично).

С латиницей всё в порядке, но когда пытаюсь записать русскоязычные символы - в БД записываются кракозябры. Испробовал уже кучу способов - пока без результатов. Пробовал записывать wstring. Пробовал отдельно из байтов формировать UTF-8 коды (char str[6] = { 208, 176, 208, 177, 208, 178 }; ). С последним вариантом, если после компиляции в Ubuntu вывести эту строку в консоль - то успешно выводит "абв", а в БД все равно записывается "абв".

Естественно, кроме этого есть и проблема того, что русскоязычная строка из запроса выглядит так %D0%B0%D0%B1%D0%B2 , но это более решаемая проблема.

Кто-нибудь в курсе, как CGI-скриптом на C++ записать в БД кириллицу?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
12.06.2017, 21:58
Ответы с готовыми решениями:

Запись формы в файл CGI скриптом на Python
Доброго всем времени суток! Мне необходимо сохранить содержимое формы в файл, используя CGI скрипты на языке Python. Данные отправляются...

не запускаеться (CGI вместе с MySQL) под Apache: Premature end of script headers: c:/www/cgi-bin/catalog.cgi
такая трабла: вот что пишет Apache в Log: Premature end of script headers: c:/www/cgi-bin/catalog.cgi main::ltimestr()...

Запись кириллицы в DBF
Имеется файл шаблон таблицы в dbf. В какой он изначально кодировке не известно (скорее всего в 866). Программе необходимо заполнить его...

13
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
12.06.2017, 22:23
Программа-то где? Как запись идёт? В какой кодировке приходит?
0
142 / 16 / 2
Регистрация: 21.01.2013
Сообщений: 54
13.06.2017, 15:47  [ТС]
Вот интересующие части кода, если это как-то поможет.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <stdio.h>
#include <stdlib.h> 
#include <iostream>
#include <string.h>
#include <mysql.h>
 
int main()
{
    char *queryString = getenv("QUERY_STRING"); // GET-запрос 
    char *name = (char*)""; // Название параметра [ТЕСТОВАЯ ПЕРЕМЕННАЯ]
    char *value = (char*)""; // Значение параметра [ТЕСТОВАЯ ПЕРЕМЕННАЯ]
    getParameter(queryString, 0, &name, &value); // Получаем значение переданного скрипту параметра
    // getParameter вместо кириллицы выдаёт коды %D0%B0%D0%B1%D0%B2 , поэтому для теста используется следующая строка
 
    //value = (char*)"ЗНАЧЕНИЕ НА РУССКОМ ДЛЯ ТЕСТА"; // кириллица
    char *result = CreateTestRecordInBD(value); // Создаём запись в БД
    cgiReturn(result); // Возвращаем результат
}
 
// Функция выполняет запрос query и в случае успеха выводит в queryResult последнюю строку результатов (или NULL) и возвращает true. В случае ошибки возвращает false.
bool QueryDB(char *query, char **queryResult)
{
    char host[] = "localhost"; // хост
    char user[] = "uXXXXXXXX_default"; // пользователь
    char passwd[] = "XXXXXX"; // пароль
    char db[] = "uXXXXXXXX_default"; // название базы данных
    
    MYSQL *connection, mysql; // Переменные для подключения к БД
    MYSQL_RES *result; // Результат запроса
    MYSQL_ROW row; // Результат запроса разделенный на строки
    int query_state; // Состояние запроса (0 - выполнен успешно, !=0 - произошла ошибка
    char res[256]; // Буфер для хранения результата запроса
 
    mysql_init(&mysql); // Инициализация MySQL
    connection = mysql_real_connect(&mysql, host, // Подключение к БД
                     user, passwd, db, 3306, 0, 0);
    if (connection == NULL) // Если не подключились - 
    { // возвращаем false
        return false;
    }
 
    query_state = mysql_query(connection, query); // Выполнение запроса
    if (query_state !=0)  // Если запрос не выполнен успешно
    { // возвращаем false
        return false;
    }
 
    result = mysql_store_result(connection); // Получаем результат запроса
    *queryResult = NULL; // значение по-умолчанию
    if (result != NULL) // Если результат не отсутствует
    {
        while (( row = mysql_fetch_row(result)) != NULL) // Получаем строку запроса. Если строк больше нет - выходим из цикла
        {
            if (strlen(row[0]) < 255) 
            {
                strcpy(res, row[0]); // выводим эту строку во временный буфер
                *queryResult = res; // выводим строку из буфера в переменную для возвращаемого значения
            }
        }
    }
 
    mysql_free_result(result); // Освобождаем переменную с результатами
    mysql_close(connection); // Закрываем соединение
 
    return true;
}
 
// Функция для создания записи в БД
char *CreateTestRecordInBD(char *code)
{
    if (code == NULL) return NULL;
    char *result = (char*)""; // Переменная для результата запроса
    char query[1024]; // Переменная для запроса к базе данных
    char *name = (char*)"Абвгдеёж";
    char *surname = (char*)"Абвгдеёжев";
    char *otchestvo = (char*)"Абвгдеёжевич";
    char *email = (char*)"abvgde@mail.ru";
    char *phone = (char*)"+7(777)7777777";
    char *dateto = (char*)"20170612";
    
    sprintf (query, "INSERT INTO `uXXXXXXX_default`.`demoUsers` (`id`, `name`, `surname`, `otchestvo`, `email`, `phone`, `code`, `dateto`) VALUES (NULL, '%s', '%s', '%s', '%s', '%s', '%s', '%s');", name, surname, otchestvo, email, phone, code, dateto);    
    
    if (QueryDB(query, &result) == false) return NULL; // Выполняем запрос
    return result; // Возвращаем result (или NULL)
}
 
// Функция для получения одного из переданных параметров
bool getParameter(char *queryString, int startPos, char **name, char **value)
{
    if (startPos >= strlen(queryString)) return false; // Если начальная позиция больше длины строки - возвращаем false
    
    int ampPos = searchSymPos(queryString, '&', startPos); // ищем положение символа & (разделяющего аргументы)
    if (ampPos == -1) // Если символ & не найден
        ampPos = strlen(queryString); // то используем всю оставшуюся строку
 
    if (ampPos - startPos < 3) // если требуемая строка с аргументом меньше 3х символов (например n=1)
        return false; // возвращаем false
 
    int eqPos = searchSymPos(queryString, '=', startPos); // ищем положение символа = (разделяющего название и значение)
    if (eqPos == -1 || // если символ = не найден
        eqPos == startPos || // или название параметра отсутствует
        eqPos > ampPos - 1) // или он найден за пределами этого параметра, или значение отстуствует
        return false; // возвращаем false
 
    *name = getSubstring(queryString, startPos, eqPos - startPos); // Название параметра
    *value = getSubstring(queryString, eqPos + 1, ampPos - eqPos - 1); // Значение параметра
 
    return true;
}
 
// Функция получения подстроки
char *getSubstring(char *fullString, int startPos, int count)
{
    if (count > 128-1) return NULL;
    char subArr[128]; 
    strncpy(subArr, fullString + startPos, count); // Копируем подстроку длины argSeparatorPos
    subArr[count] = 0; // В конце подстроки ставим нулевой бит (конец строки)
    char *substr = strdup(subArr);
    return substr;
}
 
// Функция определяет номер символа в строке
int searchSymPos(char *fullString, char sym, int startPos)
{
    int symPos = -1; // Позиция разделителя аргументов в строке
    for (unsigned int i = startPos; i < strlen(fullString); i++)
        if (fullString[i] == sym) 
        {
            symPos = i;
            return i;
        }
 
    return -1;
}
 
// Функция возвращения значения из CGI-скрипта
void cgiReturn(char *text)
{
    printf("Content-Type: text/html\r\n\r\n");
    printf("%s", text);
}
Добавлено через 17 часов 2 минуты
В общем понял, что причина вызвана тем, что используется не кодировка (charset) UTF-8, а сравнение (collation) utf8_general_ci . Только вот как в C++ записывать в таком формате кириллицу пока не знаю.
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
13.06.2017, 15:51
Если у тебя Linux, то в программе константы 74-76 и так должны быть в utf-8. Какая кодировка в системе?
0
142 / 16 / 2
Регистрация: 21.01.2013
Сообщений: 54
13.06.2017, 15:55  [ТС]
Пробовал сохранять код и в Windows-1251 и в UTF-8.

Наткнулся на эту статью:
(в спойлере ссылка на сторонний форум)
Кликните здесь для просмотра всего текста


0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
13.06.2017, 16:28
Помогло? Ты используешь SET NAMES и прочее?
0
142 / 16 / 2
Регистрация: 21.01.2013
Сообщений: 54
13.06.2017, 16:54  [ТС]
Попробовал, поместил вот такой код в main()

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    char *res = (char*)""; // Переменная для результата запроса
    char query[1024];
    strcpy(query, "SET NAMES 'utf8';");
    if (QueryDB(query, &res) == false) return 0; // Выполняем запрос
    strcpy(query, "SET CHARACTER SET 'utf8';");
    if (QueryDB(query, &res) == false) return 0; // Выполняем запрос
    strcpy(query, "SET SESSION collation_connection = 'utf8_general_ci';");
    if (QueryDB(query, &res) == false) return 0; // Выполняем запрос
    
    char *code = (char*)"абвгде"; // код
    char *result = CreateTestRecordInBD(code); // Создаём запись в БД
    
    cgiReturn(code); // Возвращаем код
        
    return 0;
Ровным счётом ничего не изменилось. В БД (смотрю через phpMyAdmin) так и отображается абвгде
Причем code (возвращенный через результат запроса) в браузере правильно отображается как UTF-8.
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
13.06.2017, 17:12
У тебя QueryDB() каждый раз переподключается, что ли? Ну тогда, конечно, работать не будет.
Внеси тогда установку этих параметров туда.
0
142 / 16 / 2
Регистрация: 21.01.2013
Сообщений: 54
13.06.2017, 17:26  [ТС]
Кликните здесь для просмотра всего текста
Пардон, это я уже туплю, сейчас исправлю.


Добавлено через 12 минут
УРАААААААААААААААААААА
Получилось!

После добавления таких строк в функцию bool QueryDB(char *query, char **queryResult) (после 41-ой строки)

C++
1
2
3
4
5
6
7
    char charsetQuery[1024];
    strcpy(charsetQuery, "SET NAMES 'utf8';");
    query_state = mysql_query(connection, charsetQuery); // Выполнение запроса
    strcpy(charsetQuery, "SET CHARACTER SET 'utf8';");
    query_state = mysql_query(connection, charsetQuery); // Выполнение запроса
    strcpy(charsetQuery, "SET SESSION collation_connection = 'utf8_general_ci';");
    query_state = mysql_query(connection, charsetQuery); // Выполнение запроса
Всё работает, и в БД записывается "абвгде" кириллицей!

Осталось ещё сделать, чтобы она вот такой код %D0%B0%D0%B1%D0%B2 правильно преобразовывала в UTF-8.
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
13.06.2017, 17:39
А зачем их копировать?
C++
1
query_state = mysql_query(connection, "SET NAMES 'utf8';");
0
142 / 16 / 2
Регистрация: 21.01.2013
Сообщений: 54
13.06.2017, 17:47  [ТС]
Уже поправил. Извиняюсь, я в основном в работе использую C#.

C++
1
2
3
    query_state = mysql_query(connection, "SET NAMES 'utf8';"); 
    query_state = mysql_query(connection, "SET CHARACTER SET 'utf8';"); 
    query_state = mysql_query(connection, "SET SESSION collation_connection = 'utf8_general_ci';");
Сейчас думаю над конвертированием кириллических параметров из URI в UTF-8.
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
13.06.2017, 17:58
Есть же какие-то готовые решения.
0
142 / 16 / 2
Регистрация: 21.01.2013
Сообщений: 54
13.06.2017, 18:00  [ТС]
Я уже видел, посмотрим. Если что - сам напишу. По крайней мере это уже не большая проблема.
0
142 / 16 / 2
Регистрация: 21.01.2013
Сообщений: 54
15.06.2017, 16:42  [ТС]
Для декодирования URL использовал следующую функцию (код не мой):

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Функция URL-декодирования.
// Функция преобразует строку данных st в нормальное представление.
// Результат помещается в ту же строку, что была передана в параметрах.
void urlDecode(char *st) 
{
    char *p=st;  // указывает на текущий символ строки
    char hex[3]; // временный буфер для хранения %XX
    int code;    // преобразованный код
    // запускаем цикл, пока не кончится строка (то есть, пока не
    // появится символ с кодом 0, см. ниже)
    do 
    {
        // Если это %-код ...
        if(*st == '%') 
        { // тогда копируем его во временный буфер
            hex[0]=*(++st); hex[1]=*(++st); hex[2]=0;
            // переводим его в число
            sscanf(hex,"%X",&code);
            // и записываем обратно в строку
            *p++=(char)code;
            // указатель p всегда отмечает то место в строке, в которое
            // будет помещен очередной декодированный символ
        }
        else // иначе, если это "+", то заменяем его на " "
            if(*st=='+') *p++=' '; 
        else *p++=*st; // а если не то, ни другое - оставляем как есть
    } while(*st++!=0); // пока не найдем нулевой код
}
Считаю, что тему можно пометить как решенную.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
15.06.2017, 16:42
Помогаю со студенческими работами здесь

Запись кириллицы в массив
Здравствуйте, форумчани. Столкнулся с проблемой. Нужно в структуру записать имена студентов, группу и 5 оценок. Но при вводе имени и...

Запись кириллицы в строку из консоли
Столкнулся с такой проблемой: если я пытаюсь заполнить строку из консоли, то потом из этой строки на экран выводятся кракозябры....

Некорректная запись кириллицы в файл
Здравствуйте! Подскажите, пожалуйста, как можно исправить (и можно ли вообще) вот такую ошибку: 1) Вводим, например, вот такие...

Запуск CGI вне cgi-bin и запуск index.cgi
Никак не получается сделать настройку 1) Запуск CGI-программ ВНЕ /cgi-bin/ 2) Запуск index.cgi в директории /cgi-bin/ если в URL нет...

Запись в txt кириллицы, появляются знаки вопроса
Всем привет, программа считывает с txt файла русские слова. И происходит их дальнейшая запись также в txt. При записи англ. слов, цифр...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru