Сайт на C++ своими руками с помощью библиотеки cgicc

Рассказываем об основах создания простого бэкенда для сайта на обычном шаред-хостинге с помощью языка C++ и библиотеки cgicc.

Серверное окружение

Если вы думаете, что бэк на C++ возможен только на выделенном сервере, это не так: большинство шаред-хостингов имеют такую возможность. Любой веб-хост, который поддерживает CGI, поддерживает и C++ скрипты.

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

Простой пример

В примере будет рассматриваться шаред-хостинг с панелью на cPanel, но описание легко адаптируется под любой другой. cPanel предоставляет отдельный каталог cgi-bin, но использовать именно его не обязательно.

Любой файл с расширением .cgi будет автоматически обработан, если имеет корректные права доступа (обычно 0755). Ниже описаны необходимые файлы (убедитесь что используете табуляцию для отступов в Makefile).

Makefile:

all:
        g++ -O3 -s hello.cpp -o hello.cgi
clean:
        rm -f hello.cgi

hello.cpp:

#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
void set_content_type(string content_type) {
  cout << “Content-type: “ << content_type << “\r\n\r\n”;
}
void set_page_title(string title) {
  cout << “<title>” << title << “</title>\n”;
}
void h1_text(string text) {
  cout << text << “\n”;
}
int main() {
  set_content_type(“text/html”);
  cout << “<!doctype html>\n”;
  cout << “<html lang=\”en\”>\n”;
  cout << “<head>\n”;
  set_page_title(“Hello, World!”);
  cout << “</head>\n”;
  cout << “<body>\n”;
  h1_text(“Hello, World!”);
  cout << “</body>\n”;
  cout << “</html>”;
  return 0;
}

Если на вашем аккаунте доступен компилятор (можно уточнить в техподдержке хостера), просто подключитесь к серверу по SSH переместите файлы в каталог public_html (можно и по FTP) и запустите в консоли:

make

Теперь попробуйте открыть файл в браузере:

http://your-test-site.com/hello.cgi

Вы должны увидеть на экране «Hello World».

Прежде, чем начать разбираться с кодом, давайте выясним, что происходит на сервере. Когда Apache получает запрос, он первым делом проверяет встроенный обработчик или RewriteRule, затем проверяет наличие запрашиваемого файла на диске. В нашем случае, он найдет hello.cgi и исполнит его: программа не принимает никаких данных, а просто возвращает строку. Apache возвращает строку в виде корректного ответа для браузера.

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

void p(string text) {
  cout << “<p>” << text << “</p>\n”;
}

Таким образом, получается аккуратная обертка для параграфа:

p(“This would be paragraph text.”);

Входные данные

Обрабатывая запросы, веб-сервер передает огромное количество информации, которая хранится в переменных окружения. Чтобы получить к ней доступ, можно воспользоваться функцией getenv() из стандартной библиотеки C (не забудьте про #include <stdlib.h> в шапке файла).

К примеру, если нужно узнать запрашиваемый URI целиком, можно использовать:

string request_uri = getenv(“REQUEST_URI”);

Вот еще несколько полезных примеров:

  • REMOTE_ADDR – получить IP адрес посетителя.
  • REQUEST_METHOD – вернет метод запроса (GET, POST и так далее).
  • DOCUMENT_ROOT – получить путь к корневому каталогу.
  • QUERY_STRING – можно использовать для получения переменных из GET.

Пример с использованием cgicc

Разбираться с переменными из GET и POST-запросами, конечно, можно и вручную, но это утомительное занятие. Нужно либо писать собственные обертки, либо использовать существующую библиотеку (в нашем примере – cgicc), которая поможет работать с HTML и обрабатывать данные форм. Использование библиотек для крупных проектов позволит сохранить уйму времени.

На Debian и Ubuntu можно устанавливать библиотеки из консоли, используя утилиту apt:

apt install libcgicc5 libcgicc5-dev

На CentOS/RHEL с установкой пакетов сложнее, так что придется использовать:

cd /usr/local/src
wget ftp://ftp.gnu.org/gnu/cgicc/cgicc-3.2.19.tar.gz
tar xfz cgicc*.tar.gz
cd cgicc*
./configure — prefix=/usr
make
make install

Обратите внимание, что версия 3.2.19 актуальна на момент написания заметки. Актуальную версию можно найти в ftp://ftp.gnu.org/gnu/cgicc/ (подключитесь по через ваш FTP-клиент).

Как только библиотека установлена, можно использовать ее в проекте. Рассмотрим пример, который принимает и обрабатывает пользовательский ввод в браузере.

Makefile:

all:
        g++ -O3 -s hello.cpp -o hello.cgi
        g++ -O3 -s cgicc.cpp -o cgicc.cgi /usr/lib/libcgicc.a
clean:
        rm -f hello.cgi cgicc.cgi

cgicc.html:

<!doctype html>
<html lang="en">
<head>
  <title>cgicc Test</title>
</head>
<body>
  <form method="POST" action="cgicc.cgi">
    <label for="name">Name</label>
    <input name="name" type="text" value="">
    <input name="submit" type="submit" value="Submit">
  </form>
</body>
</html>

cgicc.cpp:

#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace std;
using namespace cgicc;
void set_content_type(string content_type) {
  cout << “Content-type: “ << content_type << “\r\n\r\n”;
}
void set_page_title(string title) {
  cout << “<title>” << title << “</title>\n”;
}
void h1_text(string text) {
  cout << text << “\n”;
}
int main() {
  Cgicc cgi;
  string name;
  set_content_type(“text/html”);
  cout << “<!doctype html>\n”;
  cout << “<html lang=\”en\”>\n”;
  cout << “<head>\n”;
  set_page_title(“cgicc Test”);
  cout << “</head>\n”;
  cout << “<body>\n”;
  cout << “<p>”;

  name = cgi(“name”);

  if (!name.empty()) {
    cout << “Name is “ << name << “\n”;
  } else {
    cout << “Name was not provided.”;
  }
  cout << “</p>\n”;
  cout << “</body>\n”;
  cout << “</html>”;
  return 0;
}

В этом примере cgicc помогает нам парсить POST и возвращает поле name. Этот пример упрощен и данные поле при попадании на сервер не проходят дополнительную обработку, что необходимо сделать на рабочем сайте, особенно, если будет взаимодействовать с базой данных.

Производительность

C++ известен своей быстротой, но это справедливо, если вы умеете писать на нем хороший код. Интерфейс CGI также несколько замедляет скорость работы приложения, но вы все равно получаете преимущество в скорости над интерпретируемыми языками, вроде PHP.

Вас также могут заинтересовать другие статьи по теме:

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

matyushkin
29 марта 2020

ТОП-10 книг по C++: от новичка до профессионала

Книги по C++ на русском языке с лучшими оценками. Расставлены в порядке воз...
Библиотека программиста
31 января 2019

Лучшие инструменты и советы начинающему C++ программисту

Хотите изучать C++? Делимся важными навыками, фреймворками и советами, кото...