【欢迎关注编码小哥,学习更多实用的编程方法和技巧】
1、CGI基本概念
CGI是Web服务器与外部程序通信的标准接口协议
- 允许Web服务器动态生成网页内容
- 将HTTP请求转换为程序可处理的格式
- 支持多种编程语言实现CGI工作流程:
客户端请求 -> Web服务器 -> CGI程序 -> 生成响应 -> 返回客户端
2、CGI架构
[浏览器请求]
↓
[Web服务器(Apache/Nginx)]
↓
[CGI程序处理]
↓
[数据库/文件系统]
↓
[生成动态内容]
↓
[返回响应]
3、Web 服务器配置
在进行 CGI 编程之前,确保Web服务器支持CGI,所有由 HTTP 服务器执行的CGI 程序,在配置文件中配置,目录命名为 /var/www/cgi-bin。虽然CGI文件是 C++ 可执行文件,但是按照惯例它的扩展名是 .cgi。一般情况下,Apache Web 服务器会配置在 /var/www/cgi-bin 中运行 CGI 程序。也可以指定其它目录来运行CGI脚本,可以在 httpd.conf 文件中修改。
CGI程序举例
// first_cgi.cpp
#include <iostream>
#include <cstdlib>int main() {// 输出HTTP头部std::cout << "Content-Type: text/html\r\n\r\n";// HTML输出std::cout << "<html>";std::cout << "<head><title>My First CGI</title></head>";std::cout << "<body>";std::cout << "<h1>Hello, CGI World!</h1>";std::cout << "<p>Current Time: " << __TIME__ << "</p>";std::cout << "</body>";std::cout << "</html>";return 0;
}
$ tar xzf cgicc-X.X.X.tar.gz
$ cd cgicc-X.X.X/
$ ./configure --prefix=/usr
$ make
$ make install
4、CGI关键环境变量
// 常用环境变量
SERVER_NAME // 服务器主机名
SERVER_PORT // 服务器端口
REQUEST_METHOD // 请求方法(GET/POST)
QUERY_STRING // URL查询参数
REMOTE_ADDR // 客户端IP地址
CONTENT_TYPE // 请求内容类型
CONTENT_LENGTH // 请求内容长度
HTTP_USER_AGENT // 浏览器信息
5、URL GET请求
#include <iostream>
#include <cstdlib>
#include <string>
#include <sstream>
#include <map>
#include <algorithm>// URL解码函数
std::string urlDecode(const std::string& input) {std::string result;for (size_t i = 0; i < input.length(); ++i) {if (input[i] == '%') {if (i + 2 < input.length()) {char hex[3] = {input[i+1], input[i+2], '\0'};int decoded = std::stoi(hex, nullptr, 16);result += static_cast<char>(decoded);i += 2;}} else if (input[i] == '+') {result += ' ';} else {result += input[i];}}return result;
}// 解析查询字符串
class QueryParser {
private:std::map<std::string, std::string> params;public:QueryParser() {parseQueryString();}void parseQueryString() {const char* queryString = getenv("QUERY_STRING");if (!queryString) return;std::string query(queryString);std::istringstream iss(query);std::string param;while (std::getline(iss, param, '&')) {size_t pos = param.find('=');if (pos != std::string::npos) {std::string key = urlDecode(param.substr(0, pos));std::string value = urlDecode(param.substr(pos + 1));params[key] = value;}}}// 获取参数值std::string get(const std::string& key, const std::string& defaultValue = "") const {auto it = params.find(key);return (it != params.end()) ? it->second : defaultValue;}// 检查参数是否存在bool has(const std::string& key) const {return params.find(key) != params.end();}// 获取所有参数const std::map<std::string, std::string>& getAll() const {return params;}
};// 简单输入验证
bool validateInput(const std::string& input) {// 长度限制if (input.length() > 100) return false;// 检查是否包含危险字符const std::string forbiddenChars = "<>&\"';()";return std::none_of(input.begin(), input.end(), [&forbiddenChars](char c) {return forbiddenChars.find(c) != std::string::npos;});
}int main() {// 设置响应头std::cout << "Content-Type: text/html; charset=utf-8\r\n\r\n";// 创建查询解析器QueryParser query;// 开始HTML响应std::cout << "<html><head>";std::cout << "<title>URL GET 示例</title>";std::cout << "</head><body>";// 显示所有参数std::cout << "<h2>查询参数:</h2>";std::cout << "<ul>";for (const auto& param : query.getAll()) {// 安全输出if (validateInput(param.first) && validateInput(param.second)) {std::cout << "<li>" << param.first << ": " << param.second << "</li>";}}std::cout << "</ul>";// 特定参数处理示例if (query.has("name")) {std::string name = query.get("name");std::cout << "<h3>欢迎, " << name << "!</h3>";}// 年龄验证示例if (query.has("age")) {std::string ageStr = query.get("age");try {int age = std::stoi(ageStr);if (age > 0 && age < 120) {std::cout << "<p>年龄: " << age << "岁</p>";} else {std::cout << "<p>无效年龄</p>";}} catch(...) {std::cout << "<p>年龄输入无效</p>";}}// 调试信息std::cout << "<hr>";std::cout << "<h3>调试信息</h3>";std::cout << "<p>请求方法: " << (getenv("REQUEST_METHOD") ? getenv("REQUEST_METHOD") : "未知") << "</p>";std::cout << "<p>查询字符串: " << (getenv("QUERY_STRING") ? getenv("QUERY_STRING") : "无") << "</p>";std::cout << "</body></html>";return 0;
}
URL测试
// 示例调用URL
http://server/cgi-bin/get_handler.cgi?name=John&age=30&city=Beijing
表单测试
<!DOCTYPE html>
<html>
<body><form action="/cgi-bin/get_handler.cgi" method="get"><input type="text" name="name" placeholder="姓名"><input type="number" name="age" placeholder="年龄"><input type="text" name="city" placeholder="城市"><input type="submit" value="提交"></form>
</body>
</html>
编译
# 编译CGI程序
g++ -std=c++11 -o get_handler.cgi get_handler.cpp# 设置权限
chmod +x get_handler.cgi
安全增强
// 额外的输入验证
bool enhancedValidation(const std::string& input) {// 复杂验证规则if (input.empty()) return false;if (input.length() > 100) return false;// 只允许字母、数字和部分特殊字符return std::all_of(input.begin(), input.end(), [](char c) {return std::isalnum(c) || c == ' ' || c == '-' || c == '_';});
}
关键特性:
- URL解码
- 查询参数解析
- 输入验证
- 安全输出
- 错误处理
注意事项:
- 始终验证用户输入
- 使用安全的字符串处理
- 限制输入长度
- 防止注入攻击
- 合理处理异常情况