Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
RABBITSV
141 / 15 / 2
Регистрация: 21.01.2013
Сообщений: 54
#1

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

12.06.2017, 21:58. Просмотров 324. Ответов 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
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
12.06.2017, 21:58
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Запись кириллицы в БД CGI-скриптом на C++ (C++):

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

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

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

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

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

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

13
nmcf
6247 / 5559 / 2529
Регистрация: 14.04.2014
Сообщений: 23,376
12.06.2017, 22:23 #2
Программа-то где? Как запись идёт? В какой кодировке приходит?
0
RABBITSV
141 / 15 / 2
Регистрация: 21.01.2013
Сообщений: 54
13.06.2017, 15:47  [ТС] #3
Вот интересующие части кода, если это как-то поможет.

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
nmcf
6247 / 5559 / 2529
Регистрация: 14.04.2014
Сообщений: 23,376
13.06.2017, 15:51 #4
Если у тебя Linux, то в программе константы 74-76 и так должны быть в utf-8. Какая кодировка в системе?
0
RABBITSV
141 / 15 / 2
Регистрация: 21.01.2013
Сообщений: 54
13.06.2017, 15:55  [ТС] #5
Пробовал сохранять код и в Windows-1251 и в UTF-8.

Наткнулся на эту статью:
(в спойлере ссылка на сторонний форум)
Кликните здесь для просмотра всего текста
0
nmcf
6247 / 5559 / 2529
Регистрация: 14.04.2014
Сообщений: 23,376
13.06.2017, 16:28 #6
Помогло? Ты используешь SET NAMES и прочее?
0
RABBITSV
141 / 15 / 2
Регистрация: 21.01.2013
Сообщений: 54
13.06.2017, 16:54  [ТС] #7
Попробовал, поместил вот такой код в 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
nmcf
6247 / 5559 / 2529
Регистрация: 14.04.2014
Сообщений: 23,376
13.06.2017, 17:12 #8
У тебя QueryDB() каждый раз переподключается, что ли? Ну тогда, конечно, работать не будет.
Внеси тогда установку этих параметров туда.
0
RABBITSV
141 / 15 / 2
Регистрация: 21.01.2013
Сообщений: 54
13.06.2017, 17:26  [ТС] #9
Кликните здесь для просмотра всего текста
Пардон, это я уже туплю, сейчас исправлю.


Добавлено через 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
nmcf
6247 / 5559 / 2529
Регистрация: 14.04.2014
Сообщений: 23,376
13.06.2017, 17:39 #10
А зачем их копировать?
C++
1
query_state = mysql_query(connection, "SET NAMES 'utf8';");
0
RABBITSV
141 / 15 / 2
Регистрация: 21.01.2013
Сообщений: 54
13.06.2017, 17:47  [ТС] #11
Уже поправил. Извиняюсь, я в основном в работе использую 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
nmcf
6247 / 5559 / 2529
Регистрация: 14.04.2014
Сообщений: 23,376
13.06.2017, 17:58 #12
Есть же какие-то готовые решения.
0
RABBITSV
141 / 15 / 2
Регистрация: 21.01.2013
Сообщений: 54
13.06.2017, 18:00  [ТС] #13
Я уже видел, посмотрим. Если что - сам напишу. По крайней мере это уже не большая проблема.
0
RABBITSV
141 / 15 / 2
Регистрация: 21.01.2013
Сообщений: 54
15.06.2017, 16:42  [ТС] #14
Для декодирования 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
15.06.2017, 16:42
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.06.2017, 16:42
Привет! Вот еще темы с решениями:

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

Ошибка 500 cgi, нужно запустить батник через cgi
Apache на Windows (!!) Если запускаю localhost/run.bat все работает исправно,...

Perl + SSI = ошибка invalid CGI ref 'http://сервер/cgi-bin/view_bag.pl' in ....
Вопрос такой: Скрипт view_bag.pl без ошибок выполняется в папке /cgi-bin/, при...

как сделать так, чтобы создав cookies клиентским скриптом я могу получить к нему доступ серверным скриптом?
Добры день!!! Вот допустим я создаю cookie из JavaScript. В самом фале cookies...


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

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru