cgic:用于CGI编程的ANSI C库---cgic在C语言下的编程

来源:互联网 发布:西安铁路局知乎 编辑:程序博客网 时间:2024/05/16 14:03

cgic:用于CGI编程的ANSI C库

重要通知:
如果您有CGIC 1.05或更早版本,则应升级到CGIC 1.07或CGIC 2.02或更高版本,以获得重要的安全修复程序。

如果您有CGIC 2.0或CGIC 2.01,并且使用cgiCookie例程,则应升级到CGIC 2.02或更高版本,以获得重要的安全修复程序。

目录

学分和许可条款
如何获得支持
CGIC版本XYZ有哪些新功能?
什么是cgic?
获得cgic
构建和测试cgic:一个示例应用程序
如果不能编译,该怎么办
如何编写一个cgic应用程序
如何从我的cgic应用程序生成图像?
CGI调试功能:使用捕捉
cgic函数参考
cgic变量引用
cgic结果代码引用
cgic快速索引
学分和许可条款

cgic可以免费使用,只要在线提供信用通知。或者,可以购买非排他性的商业许可证,其授予在没有公共信用通知的情况下使用cgic的权利。
license.txt 有关基本许可证和商业许可证的详细信息, 请参阅文件 ,包括商业许可证的订购信息。

感谢Robert Gustavsson,Ken Holervich,Bob Nestor,Jon Ribbens,Thomas Strangert,Wu Yongwei等多年来一直对应的CGIC用户。虽然CGIC 2.x中的multipart / form-data文件上传支持的实现是我自己的,但特别要感谢那些提交自己的这个功能的实现。

如何获得支持

停!读这首!真!

您是否收到“服务器错误”,表示您的网络服务器“不能允许POST到此URL”或类似的消息?您必须配置您的WEB服务器以允许CGI程序,并且您必须在您的网络服务器需要查看的位置(或扩展)中安装CGI程序。请不要发邮件给我,除非你希望我为你配置你的Web服务器; 我肯定可以做到这个$ 50 /小时,但你可以自己解决这个问题,或者让你的网络服务器管理员这样做。
免费支持

请通过我们的联系页面提交关于CGIC的支持信息 。请注意,我们收到大量的查询,不能随时回复。有时,响应必须采取最终新版本或常见问题解答或其他文档的添加形式,而不是详细的个人响应。
小时支援

需要详细支持的人员可以安排作者Thomas Boutell的直接支持,以50美元/小时的速度直接通过信用卡付款。要安排,请通过我们的安全信息页与我们联系。为了避免延迟,请务必特别提及您希望以上述小时费率购买CGIC支持。
2.07版有什么新功能?

根据Geoff Mulligan的建议,cgic现在允许在URL编码的GET和POST提交中没有价值的密钥。虽然HTML5规范不鼓励它,但是现有的野外系统如果该值为空字符串,则完全离开=完全关闭。从2.07开始,cgic按照你的期望来处理这个事情:你得到一个包含相应的键和一个空字符串作为值的条目。还添加了一个简单的单元测试编译目标,以测试此功能并排除副作用。
2.06版有什么新功能?

Jeffrey Hutzelman慷慨贡献的一大批重要修复。 这些在平台上特别重要,在这些平台上,尝试读取请求中指出的内容长度可能会导致死锁。请看提交笔记。
2.05版的新功能?

上传文件正确关闭; 纠正资源泄漏,并使文件上传能够在具有特定文件锁定语义的平台上正常工作。
2.04版的新功能?

文档修复:手册中的cgiHtmlEscape,cgiHtmlEscapeData,cgiValueEscape和cgiValueEscapeData例程被错误地命名。版本2.04中没有代码更改。
2.03版的新功能?

支持设置Cookie已被重新实现。新代码严格遵循成功使用Cookie的网站的实际做法,而不是尝试实现规范。新代码可以在典型的网络浏览器中成功设置多个Cookie。
2.02版的新功能?

在CGIC 2.0和2.01中,如果HTTP_COOKIE环境变量与使用cgiCookieString请求的cookie的名称完全相同,则不存在任何值或等号或其他字符,则可能会发生缓冲区溢出。这不是正常的行为,不知道是否有任何实际的Web服务器允许它发生,但是我们当然会发布补丁来纠正它。感谢Nicolas Tomadakis。
cgiCookieString在cgiFormSuccess适当时返回cgiFormTruncated。固定; 感谢Mathieu Villeneuve-Belair。
现在使用简单的Set-Cookie:标题设置Cookie,并根据Chunfu Lai收集的数据,每个Cookie使用一个标题行。
Merezko Oleg修复的cgiReadEnvironment中的内存泄漏。这些内存泄漏是无法读出保存的CGI环境只有在一个正常的CGI情况经历。
2.01版的新功能?

Makefile支持“make install”
在C和C ++下编译没有警告,严格的警告和严格的ANSI兼容性
在Windows上构建(#include

int cgiMain(){#ifdef DEBUG  LoadEnvironment();#endif / * DEBUG * /  / *加载先前保存的CGI场景,如果该按钮    已被按下。* /  if(cgiFormSubmitClicked(“loadenvironment”)== cgiFormSuccess){    LoadEnvironment();  }  / *设置任何新的cookie请求。必须在*之前*    输出内容类型。* /  CookieSet();  / *发送内容类型,让浏览器知道这是HTML * /  cgiHeaderContentType( “text / html的”);  / *页面顶部* /  fprintf(cgiOut,“<HTML> <HEAD> \ n”);  fprintf(cgiOut,“<TITLE> cgic test </ TITLE> </ HEAD> \ n”);  fprintf(cgiOut,“<BODY> <H1> cgic test </ H1> \ n”);  / *如果已经点击提交按钮,请执行     提交表格。* /  if((cgiFormSubmitClicked(“testcgic”)== cgiFormSuccess)||    cgiFormSubmitClicked(“saveenvironment”)== cgiFormSuccess)  {    HandleSubmit();    fprintf(cgiOut,“<hr> \ n”);  }  / *现在显示表单* /  ShowForm();  / *完成页面* /  fprintf(cgiOut,“</ BODY> </ HTML> \ n”);  返回0;}

请注意DEBUG #ifdef。如果在编译时定义了DEBUG,可以通过在程序中插入“#define DEBUG 1”行,或者在Makefile或其他开发环境中设置DEBUG,然后调用LoadEnvironment函数。此函数调用 cgiReadEnvironment() 以恢复捕获的CGI环境以进行调试。另请参见捕获程序的讨论,该程序提供用于CGI调试。因为这是一个测试程序,所以还调用了cgiFormSubmitClicked函数来检查使用一个请求重新加载保存的CGI环境的按钮。完成的CGI程序通常不会允许最终用户作出该决定。
设置饼干

接下来,应该调用其中一个cgiHeader函数。此特定程序演示了许多功能,包括设置Cookie。如果程序员希望设置一个cookie,则必须先调用cookie设置函数,然后再输出其他头文件。这是由cgictest.c的CookieSet()函数完成的:

void CookieSet(){  char cname [1024];  char cvalue [1024];  / *必须在调用前设置cookie     cgiHeaderContentType * /  cgiFormString(“cname”,cname,sizeof(cname));    cgiFormString(“cvalue”,cvalue,sizeof(cvalue));    ifstrlen(cname)){    / * Cookie生活一天(或直到       浏览器选择摆脱它,哪个       可能立即),仅适用于       这个脚本在这个网站上。* /      cgiHeaderCookieSetString(cname,cvalue,      86400,cgiScriptName,cgiServerName);  }}

由于这是一个测试程序,因此cgiFormString 函数用于从用户先前填写的表单中获取名称和值。通常,选择cookie名称和值以满足程序员的需求,并提供一种再次识别同一用户的方法。
该cgiHeaderCookieSetString 功能通过请求Web浏览器存储它设置cookie。 从来没有任何保证,这将发生! 许多浏览器完全拒绝cookie; 其他人不一定要保持他们的要求或返回他们的价值观完好无损。使用Cookie时,始终防守防守。

cname和cvalue参数当然是cookie的值和值。第三个参数是cookie在应用程序到期之前应该在浏览器端“活”的时间(秒)在这种情况下,已经设置为86,400秒,正好是一天。 浏览器可能会也可能不会尊重这个设置,就像其他所有关于cookies一样。

第四个参数标识了Cookie认为有效的网站中的“路径”。应该为每次访问网站而发回的cookie应该设置一个路径/。在这种情况下,cookie只与CGI程序本身有关,所以 cgiScriptName(CGI程序的URL,不包括域名)被发送。类似地,cookie可以被认为与单个网站或整个域(例如 www.boutell.com整个.boutell.com 域)相关。在这种情况下,程序运行的当前站点是唯一的相关站点,因此cgiServerName用作域。

输出内容类型标题

接下来,调用cgiHeaderContentType()来指示要输出的文档的MIME类型,在这种情况下为“text / html”(一般的HTML文档)。其他一些常见的MIME类型是“image / gif”,“image / jpeg”和“audio / wav”。
请注意,可能会调用cgiHeaderStatus()或 cgiHeaderLocation()来输出错误代码或将请求重定向到其他URL。只有一个cgiHeader函数应该在程序的单个执行中被调用。

重要提示:在向用户输出任何其他响应之前, 必须调用其中一个cgiHeader函数(通常为cgiHeaderContentType())。否则,结果将不是有效的文档,并且浏览器的行为将是不可预测的。当然,如果您愿意,您可以将自己的ContentType和其他标题信息输出到cgiOut。提供cgiHeader功能为方便起见。

处理表格提交

像许多CGI程序一样,cgictest根据是否点击了各种提交按钮来做出关于其行为方式的决定。当存在testcgic或saveenvironment按钮时,cgictest调用HandleSubmit函数,该函数调用其他函数来处理表单的各个部分:

void HandleSubmit(){  名称();  地址();  饥饿();  温度();  青蛙();  颜色();  调味剂();  NonExButtons();  单选按钮();  文件();  参赛作品();  饼干();  / * saveenvironment按钮,除了提交     该形式还可以将生成的CGI场景保存到     磁盘用于以后重播与“加载保存的环境”     按钮。* /  if(cgiFormSubmitClicked(“saveenvironment”)== cgiFormSuccess){    SaveEnvironment();  }}处理文本输入cgictest的Name()函数以最简单的形式显示如下:void Name(){        名字[81];        cgiFormStringNoNewlines(“name”,name,81);        fprintf(cgiOut,“Name:”);        cgicHtmlEscape(名称);        fprintf(cgiOut,“ \ n”);}

此功能的目的是检索和显示用户输入的名称。由于程序员已经决定允许使用最多80个字符的名字,因此已经声明了一个81个字符的缓冲区(允许最后一个空字符)。该cgiFormStringNoNewlines() 则函数被调用来检索名称,并确保回车中不存在的名称(尽管某些Web浏览器不正确的行为)。第一个参数是表单中输入字段的名称,第二个参数是要复制数据的缓冲区,第三个参数是缓冲区的大小。cgic永远不会超出缓冲区的大小,并且将始终提供一个以null结尾的字符串作为响应; 如果缓冲区太小,字符串将会缩短。 如果这是不可接受的, cgiFormStringSpaceNeeded() 函数可以用来检查所需的空间量; 也可以检查cgiFormStringNoNewlines()的返回值以确定是否发生截断。请参阅 cgiFormStringNoNewlines()的完整说明。
处理输出

请注意,Name()将其HTML输出写入cgiOut而不是stdout。
由用户提交的实际名称可能会或可能不会包含在HTML中具有特殊含义的字符,具体的<,>和&字符。该cgiHtmlEscape功能用于输出用户输入的名称与这些字符中的任何出现正确转义为<,>,和&。

重要提示: cgiOut通常相当于stdout,并且使用它没有性能损失。建议您将输出写入cgiOut,以确保与不为每个cgi连接提供stdin和stdout的特殊环境的修改版本的cgic库的兼容性。

需要注意的是,在这回车文本输入区的 需要,功能cgiFormString 应改为使用。cgiFormString确保换行符总是由单个回车符(ascii十进制13)表示,使程序员的生活更轻松。请参阅cgictest.c的Address()函数的源代码。

处理单个复选框

考虑Hungry()函数,它确定用户是否选择了“饿”复选框:

void Hungry(){        if(cgiFormCheckboxSingle(“hungry”)== cgiFormSuccess){                fprintf(cgiOut,“我饿了!<BR> \ n”);        } else {                fprintf(cgiOut,“I'm not Hungry!<BR> \ n”);        }}

此函数利用 cgiFormCheckboxSingle()函数,该函数确定是否选择了单个复选框。cgiFormCheckboxSingle()接受的复选框作为其唯一的参数的名称属性,并返回 cgiFormSuccess如果选择了复选框,或 cgiFormNotFound如果它不是。如果使用了同名的多个复选框,请考虑使用 cgiFormCheckboxMultiple()和 cgiFormStringMultiple() 函数。
处理数字输入

现在考虑Temperature()函数,它以度为单位检索温度(浮点值),并确保它处于特定范围内:
void Temperature(){
双温;
cgiFormDoubleBounded(“temperature”,&temperature,80.0,120.0,98.6);
fprintf(cgiOut,“我的温度是%f。
\ n”,温度);
}
温度由函数cgiFormDoubleBounded()检索 。第一个参数是表单中温度输入字段的名称; 第二个参数指向将包含结果的变量的地址。接下来的两个参数分别是下限和上限。最后一个参数是用户没有提交值时返回的默认值。
此函数始终在指定范围内检索合理的值; 高于或低于界限的值被限制为适合边界。但是,可以检查cgiFormDoubleBounded的返回值,以确保实际的用户条目是边界,而不是空格等等; 有关详细信息,请参阅 cgiFormDoubleBounded()的说明。如果不需要边界检查,请考虑使用 cgiFormDouble()。

请注意,对于整数输入,函数 cgiFormInteger和 cgiFormIntegerBounded 是可用的。这些功能的行为与上述浮点数相似。

处理单选输入

HTML的标签用于为用户提供多种选择。当选择次数相对较少时,单选按钮和复选框也可以使用。考虑cgictest.c的Color()函数:

char * colors [] = {        “红”,        “绿色”,        “蓝色”};void Color(){        int colorChoice;        cgiFormSelectSingle(“colors”,colors,3,&colorChoice,0);        fprintf(cgiOut,“我是:%s <BR> \ n”,colors [colorChoice]);}

此功能确定用户从表单中的列表中选择了几种颜色。声明一系列颜色; 所述cgiFormSelectSingle() 然后函数被调用,以确定,如果有的话,这些选择的被选中。第一个参数表示表单中输入字段的名称。第二个参数指向可接受颜色的列表。第三个参数表示颜色数组中的条目数。第四个参数指向将接受所选颜色的变量,最后一个参数表示浏览器未提交选择时要设置的默认值的索引。
cgiFormSelectSingle()将始终指示合理的选择值。但是,如果程序员希望知道实际提交的值,则提交的值是法定响应,依此类推,可以查询cgiFormSelectSingle()的返回值。有关详细信息,请参阅cgiFormSelectSingle()的完整说明 。

请注意,单选按钮组和列表都可以通过此功能来处理。如果您正在处理单选按钮组,您可能更喜欢调用 相同功能的cgiFormRadio()。

“如果我不知道运行时可接受的选择怎么办?

如果在运行时才可以接受选择,那么可以简单地从磁盘加载选项。但是,如果可接受的选择根本不固定(考虑国名的列表;可以随时添加新的名称,更新程序代码或单独的国家列表也是不方便的),只需调用 cgiFormStringNoNewlines (), 而不是直接检索字符串。请记住,如果您这样做,验证响应以确保它是安全和合法的成为您自己的程序解决的问题。cgiFormSelectSingle()的优点是从不返回无效响应。

要处理具有相同名称的多选列表和复选框组,请参阅下面的cgictest.c的NonExButtons()函数的讨论。

处理多选择输入

考虑cgictest.c的NonExButtons()函数的前半部分:

char * votes [] = {  “一个”,  “B”,  “C”,  “D”};void NonExButtons(){  int voteChoices [4];  int i  int结果;    int无效;  char **响应;  / *方法1:检查有效投票。这是一个好主意,    因为对不存在的候选人的投票应该是可能的    被打折... * /  fprintf(cgiOut,“投票(方法1):<BR> \ n”);  result = cgiFormCheckboxMultiple(“vote”,votes,4,    投票选票,无效);  if(result == cgiFormNotFound){    fprintf(cgiOut,“我讨厌他们所有!<p> \ n”);  } else {      fprintf(cgiOut,“我的首选候选人是:\ n”);    fprintf(cgiOut,“<ul> \ n”);    for(i = 0;(i <4); i ++){      if(voteChoices [i]){        fprintf(cgiOut,“<li>%s \ n”,票[i]);      }    }    fprintf(cgiOut,“</ ul> \ n”);  }  ```此函数利用了 cgiFormCheckboxMultiple(),用于标识一个或多个具有相同名称的所选复选框。此函数与cgiFormSelectMultiple()执行相同的 操作。也就是说,具有MULTIPLE属性的<SELECT>标签就像一组具有相同名称的多个复选框一样被处理。cgiFormCheckboxMultiple() 的第一个参数是给组中所有复选框输入字段的名称。第二个参数指向一系列合法值; 这些应该对应于复选框的VALUE属性(或<SELECT>列表中的OPTION标签)。第三个参数指示合法值数组中的条目数。第四个参数指向具有与合法值数组相同数量的条目的整数数组; 如果选中此复选框或选项,则每个条目都将设置为true,否则为false。最后一个参数指向一个整数,它将被设置为提交的无效响应(响应不在有效响应数组中)的数量。如果该值不感兴趣,最后一个参数可能是空指针(0)。请注意,检查cgiFormCheckboxMultiple的返回值以确定是否设置了任何选项。有关 其他可能的返回值,请参阅cgiFormCheckboxMultiple的完整说明 。“如果我不知道运行时可接受的选择怎么办?如果在运行时才可以接受选择,那么可以简单地从磁盘加载选项。但是,如果可接受的选择根本不是固定的(请考虑一下冰激凌的风味;可以随时添加新的名称,更新程序代码或单独的国家列表也是不方便的)需要动态的方法。考虑cgictest.c的NonExButtons()函数的下半部分:  / *方法#2:获得所有投票的名称并信任他们。    如果表格会更频繁地变化,这很好    比代码和发明的反应不是一个危险    或者可以以其他方式检查。* /    ```  fprintf(cgiOut,“投票(方法2):<BR> \ n”);  result = cgiFormStringMultiple(“vote”,&responses);  if(result == cgiFormNotFound){      fprintf(cgiOut,“我讨厌他们所有!<p> \ n”);  } else {    int i = 0;    fprintf(cgiOut,“我的首选候选人是:\ n”);    fprintf(cgiOut,“<ul> \ n”);    while(respond [i]){      fprintf(cgiOut,“<li>%s \ n”,responses [i]);      我++;    }    fprintf(cgiOut,“</ ul> \ n”);  }  / *我们必须确保释放字符串数组或内存    会发生泄漏。只需调用free()就可以自由    数组而不是单个字符串。该    函数cgiStringArrayFree()完成该作业。* /    cgiStringArrayFree(responses);}

该代码片段演示了检索选项列表的另一种方法。函数 cgiFormStringMultiple()用于检索由特定输入字段名称提交的所有字符串组成的数组。这对于具有MULTIPLE属性的标签和具有相同名称的复选框组都起作用。
cgiFormStringMultiple() 的第一个参数是有问题的输入字段或输入字段组的名称。第二个参数应该是一个指向一个字符串的指针的指针的地址,而不是它的声音。考虑以下简单调用函数:

/ *一串数组; 每个C字符串是一个字符数组* /char **响应; cgiFormStringMultiple(“vote”,&responses);“我怎么知道有多少回应?”在调用之后,字符串数组中的最后一个条目将是空指针。因此简单循环:int i = 0;while(respond [i]){  / *用字符串响应[i] * /  我++;}

可以用来遍历数组,直到遇到最后一个条目。
重要提示:在 cgiFormStringMultiple函数返回一个指针来分配内存。您的代码不应修改响应数组或响应数组本身中的字符串; 如果需要修改,则应该复制字符串。当您的代码完成检查响应数组时,您必须调用 cgiStringArrayFree()作为参数释放与数组关联的内存。否则,在程序存在之前,内存将不再可用。不要只调用free()函数; 如果你这样做,单个的字符串不会被释放。

访问已上传的文件

CGIC提供访问作为表单提交的一部分上传的文件的功能。重要信息:您必须设置标签的enctype属性form才能multipart/form-data使此功能正常工作!例如,请参阅下面的cgictest.c的ShowForm函数。
Filecgictest.c 的功能负责接收上传的文件:

void File(){  cgiFilePtr文件;  字符名[1024];  char contentType [1024];  char缓冲区[1024];  int大小  int得到  if(cgiFormFileName(“file”,name,sizeof(name))!=     cgiFormSuccess)   {    printf(“<p>没有上传文件<p> \ n”);    返回;  }         fprintf(cgiOut,“提交的文件名为:”);        cgiHtmlEscape(名称);        fprintf(cgiOut,“<p> \ n”);        cgiFormFileSize(“file”,&size);        fprintf(cgiOut,“文件大小为:%d bytes <p> \ n”,size);        cgiFormFileContentType(“file”,contentType,sizeof(contentType));        fprintf(cgiOut,“该文件的所谓内容类型为:”);        cgiHtmlEscape(contentType中);        fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“当然这只是声称浏览器”    “上传文件时,就像文件名一样,    “它不能被信任。<p> \ n”);  fprintf(cgiOut,“该文件的内容如下所示:<p> \ n”);  if(cgiFormFileOpen(“file”,&file)!= cgiFormSuccess){    fprintf(cgiOut,“无法打开文件。<p> \ n”);    返回;  }  fprintf(cgiOut,“<pre> \ n”);  while(cgiFormFileRead(file,buffer,sizeof(buffer),&got)==    cgiFormSuccess)  {    cgiHtmlEscapeData(buffer,got);  }  fprintf(cgiOut,“</ pre> \ n”);  cgiFormFileClose(文件);}

首先,文件功能检查确定用户提交的文件名。非常重要:这个文件名可能会或可能不会承担任何关系到用户的计算机上的文件的真实姓名,可以用恶意地故意操纵, 并且不应该被用于任何目的,除非你确定它的内容是安全的您的预期用途,至少不会覆盖对您重要的另一个文件,特别是如果您打算在服务器端使用它作为文件名。cgic库本身不使用此文件名进行临时存储。
如果cgiFormFileName函数不成功,则不会上传任何文件。

接下来,调用cgiFormFileSize函数来确定上传文件的大小(以字节为单位)。

然后,文件功能继续查询上传文件的内容类型。由用户上传的文件具有自己的内容类型信息,这可以用于确定文件是图像,HTML文档,文字处理文档还是其他类型的文件。然而, 与浏览器所做的文件名和任何其他声明一样,此信息不应盲目信任。浏览器可以上传具有名称picture.jpg和内容类型的文件image/jpeg,但这并不能保证实际文件将包含适合显示的有效JPEG图像。

浏览器提交的内容类型可以使用cgiFormFileContentType函数进行查询 。

当然,CGIC还提供访问实际的uploded文件。首先,程序员调用cgiFormFileOpen,传递一个cgiFilePtr对象的地址。如果此函数成功,cgiFilePtr对象将变为有效,并可用于对cgiFormFileRead的后续调用。请注意,读取的字节数可能小于请求的数量,特别是在cgiFormFileRead开始返回之前的最后一次成功调用cgiFormEOF。当cgiFormFileRead不再返回cgiFormSuccess时,程序员调用cgiFormFileClose释放该cgiFilePtr对象。

上传的文件数据可能包含任何内容,包括二进制数据,空字符等。示例程序使用 cgiHtmlEscapeData函数输出具有HTML转义意义的任何特殊字符的数据。大多数程序将上传的信息保存到服务器端文件或数据库。

获取所有表单条目

程序员可能不时提前知道所有表单字段的名称。在这种情况下,使用cgiFormEntries函数是方便的。cgictest.c的Entries函数演示了使用cgiFormEntries:

void Entries(){        char ** array,** arrayStep;        fprintf(cgiOut,“所有提交的表单域名称列表:<p> \ n”);        if(cgiFormEntries(&array)!= cgiFormSuccess){                返回;        }        arrayStep = array;        fprintf(cgiOut,“<ul> \ n”);        while(* arrayStep){                fprintf(cgiOut,“<li>”);                cgiHtmlEscape(* arrayStep);                fprintf(cgiOut,“\ n”);                arrayStep ++;        }        fprintf(cgiOut,“</ ul> \ n”);        cgiStringArrayFree(数组);}

cgiFormEntries函数检索表单字段名称的数组。该数组由指向字符串的指针组成,最后一个空指针用于标记列表的末尾。上面的代码说明了循环返回的字符串的一种方式。注意对cgiStringArrayFree的最终调用 ,这是为了返回用于存储字符串和字符串数组的内存所必需的。
检索饼干

cgictest.c的Cookie功能会显示浏览器提交的所有Cookie以及当前表单提交的列表及其值:

void Cookies(){  char ** array,** arrayStep;  char cname [1024],cvalue [1024];  fprintf(cgiOut,“在此呼叫中提交的Cookie,带值”    “(许多浏览器不提交Cookie):<p> \ n”);  if(cgiCookies(&array)!= cgiFormSuccess){    返回;  }  arrayStep = array;  fprintf(cgiOut,“<table border = 1> \ n”);  fprintf(cgiOut,“<tr> <th> Cookie <th> Value </ tr> \ n”);  while(* arrayStep){    char值[1024];    fprintf(cgiOut,“<tr>”);    fprintf(cgiOut,“<td>”);    cgiHtmlEscape(* arrayStep);    fprintf(cgiOut,“<td>”);    cgiCookieString(* arrayStep,value,sizeof(value));    cgiHtmlEscape(值);    fprintf(cgiOut,“\ n”);    arrayStep ++;  }  fprintf(cgiOut,“</ table> \ n”);  cgiFormString(“cname”,cname,sizeof(cname));    cgiFormString(“cvalue”,cvalue,sizeof(cvalue));    if(strlen(cname)){    fprintf(cgiOut,“这个调用的新Cookie设置:<p> \ n”);    fprintf(cgiOut,“Name:”);      cgiHtmlEscape(CNAME);    fprintf(cgiOut,“Value:”);      cgiHtmlEscape(cvalue);    fprintf(cgiOut,“<p> \ n”);    fprintf(cgiOut,“如果您的浏览器接受cookies”      “(很多不要),这个新的cookie应该出现”      “在上面的列表中,下一次表单是”      “提交<P> \ n”);   }  cgiStringArrayFree(数组);}

非常重要:您的浏览器可能不会提交COOKIES,无论您输入测试表的值如何。 许多浏览器被配置为不接受或发送cookie; 其他人被配置为尽可能少地发送它们以满足进入热门站点的最低限度的要求。用户经常拒绝您的cookies; 确保您的代码仍然在这种情况下工作!
上述代码使用cgiCookies函数来检索所有当前设置的cookie的列表,作为一个以null结尾的字符串数组。该cgiCookieString 函数然后被用于获取与每个cookie相关联的值; 这个功能很像cgiFormString,前面讨论过。请注意,作为当前表单提交过程的一部分设置的Cookie不会立即显示在此列表中,因为浏览器尚未发送回来。它应该出现在未来的提交中,只要浏览器选择接受并重新发送cookie。

显示提交到当前程序的表单

CGI程序员通常需要显示HTML页面作为CGI程序输出的一部分; 这些HTML页面通常包含应该将字段提交回他们来自相同程序的表单。如果您的Web服务器配置良好,可以使用cgiScriptName环境变量方便地完成,如下所示。这是cgictest.c的ShowForm函数的源代码:

void ShowForm(){  fprintf(cgiOut,“<! -  2.0:multipart / form-data是必需的     “文件上传” - >“);  fprintf(cgiOut,“<form method = \”POST \“”    “enctype = \”multipart / form-data \“”);  fprintf(cgiOut,“action = \”“);  cgiValueEscape(cgiScriptName);  fprintf(cgiOut,“\”> \ n“);  fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“Text Field contains Plaintext \ n”);  fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“<input type = \”text \“name = \”name \“>您的姓名\ n”);  fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“多行文本字段\ n”);  fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“<textarea NAME = \”add​​ress \“ROWS = 4 COLS = 40> \ n”);  fprintf(cgiOut,“默认内容去这里\ n”);  fprintf(cgiOut,“</ textarea> \ n”);  fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“Checkbox \ n”);  fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“<input type = \”checkbox \“name = \”hungry \“checked> Hungry \ n”);  fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“包含数值的文本字段\ n”);  fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“<input type = \”text \“name = \”temperature \“value = \”98.6 \“> \ n”);  fprintf(cgiOut,“Blood Temperature(80.0-120.0)\ n”);  fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“Text Field contains a Integer Value \ n”);  fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“<input type = \”text \“name = \”frogs \“value = \”1 \“> \ n”);  fprintf(cgiOut,“Frogs Eaten \ n”);  fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“Single-SELECT \ n”);  fprintf(cgiOut,“<br> \ n”);  fprintf(cgiOut,“<select name = \”colors \“> \ n”);  fprintf(cgiOut,“<option value = \”Red \“> Red \ n”);  fprintf(cgiOut,“<option value = \”Green \“> Green \ n”);  fprintf(cgiOut,“<option value = \”Blue \“> Blue \ n”);  fprintf(cgiOut,“</ select> \ n”);  fprintf(cgiOut,“<br> \ n”);  fprintf(cgiOut,“Multiple-SELECT \ n”);  fprintf(cgiOut,“<br> \ n”);  fprintf(cgiOut,“<select name = \”flavors \“multiple> \ n”);  fprintf(cgiOut,“<option value = \”开心果\“开心果\ n”);  fprintf(cgiOut,“<option value = \”walnut \“>核桃\ n”);  fprintf(cgiOut,“<option value = \”creme \“> Creme \ n”);  fprintf(cgiOut,“</ select> \ n”);  fprintf(cgiOut,“<p>独家无线电按钮组:”年龄“    “卡车在几年\ n”);  fprintf(cgiOut,“<input type = \”radio \“name = \”age \“”    “值= \” 1 \ “> 1个\ n”);  fprintf(cgiOut,“<input type = \”radio \“name = \”age \“”    “值= \” 2 \ “> 2 \ n”);  fprintf(cgiOut,“<input type = \”radio \“name = \”age \“”    “value = \”3 \“checked> 3 \ n”);  fprintf(cgiOut,“<input type = \”radio \“name = \”age \“”    “值= \” 4 \ “> 4 \ n”);  fprintf(cgiOut,“<p>无关的复选框组:”    “通过四名候选人投票\ n”);  fprintf(cgiOut,“<input type = \”checkbox \“name = \”vote \“”    “值= \” A \ “> A \ n” 个);  fprintf(cgiOut,“<input type = \”checkbox \“name = \”vote \“”    “值= \” B \ “>乙\ n”);  fprintf(cgiOut,“<input type = \”checkbox \“name = \”vote \“”    “值= \” C \ “>Ç\ n”);  fprintf(cgiOut,“<input type = \”checkbox \“name = \”vote \“”    “值= \” D \ “>Ð\ n”);  fprintf(cgiOut,“<p>文件上传:\ n”);  fprintf(cgiOut,“<input type = \”file \“name = \”file \“”    “value = \”\“>(选择本地文件)\ n”);  fprintf(cgiOut,“<p> \ n”);  fprintf(cgiOut,“<p>设置Cookie <p> \ n”);  fprintf(cgiOut,“<input name = \”cname \“”    “value = \”\“> Cookie名称\ n”);  fprintf(cgiOut,“<input name = \”cvalue \“”    “value = \”\“> Cookie Value <p> \ n”);  fprintf(cgiOut,“<input type = \”submit \“”    “name = \”testcgic \“value = \”Submit Request \“> \ n”);  fprintf(cgiOut,“<input type = \”reset \“”    “value = \”Reset Request \“> \ n”);  fprintf(cgiOut,“<p>保存CGI环境<p> \ n”);  fprintf(cgiOut,“按此按钮将提交表单,然后”    “保存CGI环境,以便稍后再播放”    “通过调用cgiReadEnvironment(在调试器中,为”    “实例)<P> \ n”);  fprintf(cgiOut,“<input type = \”submit \“name = \”saveenvironment \“”    “value = \”保存环境\“> \ n”);  fprintf(cgiOut,“</ form> \ n”);}

注意enctype=”multipart/form-data”在 FORM标签中使用。如果表单中包含文件上传字段,则是绝对必需的,如上例所示。大多数浏览器甚至不会在没有此属性的情况下尝试文件上传。
检查CGI环境变量

CGI标准规定了服务器设置的环境变量的数量。但是,当环境变量未设置时,服务器在这些变量是否为空或指向空字符串时有些不可预测。此外,为了让程序员能够恢复保存的CGI环境,cgic库需要一种将程序员与实际环境变量隔离的方法。
不要调用getenv()来确定诸如HTTP_USER_AGENT(正在使用的浏览器软件)之类的变量的值,所以总是使用环境变量的 cgic副本,它们总是有效的C字符串(尽管它们可以指向到一个空字符串)。例如,包含浏览器软件名称的cgic变量是 cgiUserAgent。引用URL出现在变量cgiReferrer中。

如何从我的cgic应用程序生成图像?

cgic可以与gd图形库一起使用 ,可以在GIF中快速生成图像。
以下简短示例程序提示了可能性:

#include“cgic.h”#include“gd.h”char * colors [] = {  “红”,“绿”,“蓝”};#define colors总共3int cgiMain(){  int colorChosen;  gdImagePtr im;  int r,g,b;  / *使用gd创建图像* /  im = gdImageCreate(6464);  r = gdImageColorAllocate(im,25500);    g = gdImageColorAllocate(im,02550);    b = gdImageColorAllocate(im,00255);    / *现在使用cgic来找出用户请求的颜色* /  cgiFormSelectSingle(“color”,3,&colorChosen,0);    / *现在填写所需的颜色* /  开关(colorChosen){    情况0:    gdImageFill(im,3232,r);    打破;    情况1:    gdImageFill(im,3232,g);    打破;    情况2:    gdImageFill(im,3232,b);    打破;  }    / *现在输出图像。注意内容类型!* /  cgiHeaderContentType( “图像/ GIF”);  / *将图像发送到cgiOut * /  gdImageGif(im,cgiOut);  / *释放gd图像* /  gdImageDestroy(IM);  返回0;}

请注意,此程序需要与cgic.o和libgd.a相关联。通常,这种类型的程序通过返回具有内联图像引用的HTML页面来响应一个cgiPathInfo值或一组表单域,而后者又产生一个GIF图像。
调试CGI应用程序:使用捕获

调试CGI应用程序可能是一项艰巨的任务。由于CGI应用程序在由Web服务器创建的特殊环境中运行,所以很难在调试器中执行它们。但是,cgic库提供了一种将“实时”CGI环境捕获到文件中的方法,并且还提供了重新加载保存的环境的方法。
提供的程序“capture.c”可用于捕获CGI环境。只需更改capture.c的cgiMain()函数的第一行,将CGI环境保存到适合您系统的文件名,然后键入’make capture’。然后将捕获放置在您的cgi目录中,并设置要测试的表单操作或其他链接来指向它。当表单提交或其他链接发生时,捕获将将CGI环境当前激活到源中指定的文件名。该 cgiReadEnvironment()函数然后可以在相同的文件名,在你想以恢复所捕获的环境中测试应用程序的cgiMain()函数的调用开始。然后,您可以在选择的调试器中执行程序,

重要提示:确保指定完整路径,因为CGI脚本的当前工作目录可能不是您认为的!

更重要的是:如果你调用的getenv()自己在你的代码,而不是使用所提供 的CGI环境变量的副本CGIC,你会 不会得到一个保存的CGI环境中运行时,您所期望的值。始终使用cgic变量而不是调用getenv()。

cgic函数参考

cgiFormResultType cgiFormString(char * name,char * result,int max) cgiFormString尝试检索为指定的输入字段发送的字符串。文本将被复制到由result指定的缓冲区中,最多不超过max-1个字节; 然后添加一个终止null以完成该字符串。不管浏览器提交的换行符格式如何,cgiFormString始终将每个换行符编码为单个换行符(ascii十进制10); 因此,最终的字符串可能比通过调用 cgiFormStringSpaceNeeded指示的稍短,但永远不会更长。cgiFormString返回cgiFormSuccess如果字符串顺利取出, cgiFormTruncated如果字符串被检索,但被截断以适应缓冲区,如果字符串被检索但空cgiFormEmpty,如果没有提交这样的输入字段,则cgiFormNotFound。在最后一种情况下,将空字符串复制到结果。 cgiFormResultType cgiFormStringNoNewlines(char * name,char * result,int max) cgiFormStringNoNewlines()完全等同于 cgiFormString(),除了任何回车或输入中发生的换行符将被删除。对于单行文本输入字段,建议使用此功能,因为某些浏览器不应该提交回车符和换行符。 cgiFormResultType cgiFormStringSpaceNeeded(char * name,int * length) cgiFormStringSpaceNeeded()用于确定接收指定输入字段内容所需的输入文本缓冲区的长度。如果程序员希望为任意长度的输入分配足够的存储空间,这是有用的。通过后续调用cgiFormString()检索的字符串的实际长度可能稍短,但永远不会超过*结果。成功后,cgiFormStringSpaceNeeded()将长度指向的值设置为数据的字节数,包括终止null,并返回cgiFormSuccess。如果没有为指定的字段提交值,cgiFormStringSpaceNeeded将指向的长度值设置为1,并返回cgiFormNotFound。 cgiFormResultType cgiFormStringMultiple(char * name,char *** ptrToStringArray) cgiFormStringMultiple在异常情况下很有用,其中表单中的多个输入元素具有相同的名称,无论何种原因,程序员都不希望使用下面提供的复选框,单选按钮和选择菜单功能。如果程序员无法预先知道表单中的多选列表或复选框中可能显示哪些值,则这是偶尔需要的。结果指向的值将被设置为指向字符串数组的指针; 数组中的最后一个条目将是空指针。该数组由CGI库分配。重要提示:使用数组时,必须使用数组指针作为参数调用cgiStringArrayFree()。cgiFormStringMultiple()返回cgiFormSuccess,如果发现至少有一个名字,cgiFormNotFound 如果没有发生任何事件,或者cgiFormMemory如果没有足够的内存可用于分配要返回的数组。在所有情况下,除了最后一个,ptrToStringArray设置为指向一个有效的字符串数组,数组中的最后一个元素是一个空指针; 在内存不足的情况下,ptrToStringArray设置为空指针。 cgiFormResultType cgiFormEntries(char *** ptrToStringArray) 当程序员不能提前知道所有相关表单字段的名称时,cgiFormEntries是有用的。结果指向的值将被设置为指向字符串数组的指针; 数组中的最后一个条目将是空指针。该数组由CGI库分配。重要提示:使用数组时,必须使用数组指针作为参数调用cgiStringArrayFree()。cgiFormEntries()返回cgiFormSuccess,除非出现内存不足错误。成功时,ptrToStringArray设置为指向一个有效的字符串数组,数组中的最后一个元素是空指针; 在内存不足情况下,ptrToStringArray设置为空指针,并 返回cgiFormOutOfMemory。 void cgiStringArrayFree(char ** stringArray) cgiStringArrayFree()用于释放与由cgiFormStringMultiple(), cgiFormEntries()或 cgiFormCookies()创建的字符串数组相关联的内存 。 cgiFormResultType cgiFormInteger(char * name,int * result,int defaultV) cgiFormInteger()尝试检索为指定的输入字段发送的整数。结果指向的值将被设置为提交的值。cgiFormInteger()如果值成功检索,则返回cgiFormSuccess,如果提交的值为空字符串,则为cgiFormEmpty,如果提交的值不是整数,则为cgiFormBadType,如果未提交此类输入字段,则为cgiFormNotFound。在最后三种情况下,结果指向的值设置为指定的默认值。 cgiFormResultType cgiFormIntegerBounded(char * name,int * result,int min,int max,int defaultV) cgiFormIntegerBounded()尝试检索为指定的输入字段发送的整数,并将结果限制在指定的范围内。结果指向的值将被设置为提交的值。cgiFormIntegerBounded()返回cgiFormSuccess,如果值成功检索, cgiFormConstrained如果值超出了界限,结果被相应地调整,cgiFormEmpty如果提交的值是一个空字符串,cgiFormBadType如果提交的值不是整数,cgiFormNotFound如果没有提交了这样的输入字段。在最后三种情况下,结果指向的值设置为指定的默认值。 cgiFormResultType cgiFormDouble(char * name,double * result,double defaultV) cgiFormDouble尝试检索为指定的输入字段发送的浮点值。结果指向的值将被设置为提交的值。如果成功检索到该值,则cgiFormDouble返回cgiFormSuccess,如果提交的值为空字符串,则为cgiFormEmpty,如果提交的值不是数字,则为cgiFormBadType,如果未提交此类输入字段,则为cgiFormNotFound。在最后三种情况下,结果指向的值设置为指定的默认值。 cgiFormResultType cgiFormDoubleBounded(char * name,double * result,double min,double max,double defaultV) cgiFormDoubleBounded()尝试检索为指定的输入字段发送的浮点值,并将结果限制在指定的范围内。结果指向的值将被设置为提交的值。cgiFormDoubleBounded()返回cgiFormSuccess如果该值被成功地检索, cgiFormConstrained如果该值没有被绑定和结果相应的调整,cgiFormEmpty如果提交的值是空字符串,cgiFormBadType如果提交的值不是数字,和cgiFormNotFound如果没有提交了这样的输入字段。在最后三种情况下,结果指向的值设置为指定的默认值。 cgiFormResultType cgiFormSelectSingle(char * name,char ** choicesText,int choicesTotal,int * result,int defaultV) cgiFormSelectSingle()检索与不允许多个选择的<SELECT>元素相关联的选择编号。名称应该标识<SELECT>元素的NAME属性。choicesText应指向每个选择的字符串数组; choicesTotal应该指出总数量的选择。结果指向的值将被设置为selectionText数组(如果有的话)中选择的实际选择的位置,或者如果没有提交选择或无效的选择,则设置为默认值。cgiFormSelectSingle()返回cgiFormSuccess如果该值被顺利取出,cgiFormNotFound如果没有选择提交,cgiFormResultType cgiFormSelectMultiple(char * name,char ** choicesText,int choicesTotal,int * result,int * invalid) cgiFormSelectMultiple()检索与允许多个选择的<SELECT>元素相关联的选择数字。名称应该标识<SELECT>元素的NAME属性。choicesText应指向每个选择的字符串数组; choicesTotal应该指出总数量的选择。结果应该指向一个整数数组,其数量与selectionText数组中的字符串一样多。对于所选的choicesText数组中的每个选择,结果数组中的相应整数将被设置为1; 结果数组中的其他条目将被设置为零。 如果至少有一个有效的选择被成功检索,cgiFormSelectMultiple()返回cgiFormSuccess,如果没有提交有效的选择,则cgiFormNotFound。 cgiFormResultType cgiFormSubmitClicked(char * name) 当存在具有不同名称属性的多个提交按钮时,通常需要知道特定的提交按钮是否被点击。cgiFormSubmitClicked是cgiFormCheckboxSingle函数的替代名称 ,适用于测试是否使用特定的提交按钮。cgiFormResultType cgiFormCheckboxSingle(char * name) cgiFormCheckboxSingle确定是否选中了具有指定名称的复选框。cgiFormCheckboxSingle返回cgiFormSuccess如果按钮被选中,cgiFormNotFound如果复选框未被选中。cgiFormCheckboxSingle用于具有唯一名称的单个复选框; 请参阅下面的功能来处理具有相同名称的多个复选框以及单选按钮。 cgiFormResultType cgiFormCheckboxMultiple(char * name,char ** valuesText,int valuesTotal,int * result,int * invalid) cgiFormCheckboxMultiple()确定在一组具有相同名称的复选框中选中哪个复选框。这与单选按钮不同(见cgiFormRadio)。valuesText应指向一个字符串数组,标识每个复选框的VALUE属性; valuesTotal应该指示复选框的总数。结果应该指向具有与valuesText数组中的字符串一样多的元素的整数数组。对于所选的valuesText数组中的每个选择,结果数组中的相应整数将被设置为1; 结果数组中的其他条目将被设置为零。如果至少有一个有效的复选框被选中,cgiFormCheckboxMultiple返回cgiFormSuccess,如果没有选中有效的复选框,则返回cgiFormNotFound。 cgiFormResultType cgiFormRadio(char * name,char ** valuesText,int valuesTotal,int * result,int defaultV) cgiFormRadio()确定选择了一组具有相同名称的无线电框的哪个(如果有的话)。valuesText应指向标识每个单选框的VALUE属性的字符串数组; valuesTotal应该指示收音机的总数。结果指向的值将被设置为在valuesText数组(如果有)中选择的实际选择的位置,或者如果没有选中单选框或无效选择,则设置为默认值。cgiFormRadio()返回cgiFormSuccess如果选中的无线电盒被该组中发现,cgiFormNotFound如果没有框进行检查, cgiFormNoSuchChoice如果提交的无线电盒不匹配任何的valuesText阵列中的可能性。 cgiFormResultType cgiFormFileName(char * name,char * fileName,int max) cgiFormFileName尝试检索由用户为指定的表单输入字段类型上传的文件名file。 从来没有信任这个文件名称是合理的,并且安全地在服务器端直接使用。 文本将被复制到由fileName指定的缓冲区中,最多不超过max-1个字节; 然后添加一个终止null以完成该字符串。cgiFormFileName返回 cgiFormSuccess如果字符串检索成功,是不是空的, cgiFormNoFileName如果字符串检索成功,但为空,表明没有文件被上传, cgiFormTruncated如果字符串被检索,但被截断以适应缓冲区,如果没有提交这样的输入字段,则cgiFormNotFound。在最后一种情况下,将空字符串复制到结果。 cgiFormResultType cgiFormFileSize(char * name,int * sizeP) cgiFormFileSize尝试检索由浏览器上传的文件的大小(以字节为单位),以响应file由name参数指定 的类型的输入字段。成功后,将大小存储到* sizeP,此函数返回 cgiFormSuccess。如果表单字段不存在,则此函数返回 cgiFormNotFound。如果表单字段存在但没有上传文件,则此函数返回cgiFormNotAFile。 cgiFormResultType cgiFormFileContentType(char * name,char * contentType,int max) cgiFormString尝试检索用户为指定的表单输入字段类型声明的内容名称file。 内容类型将不会保证是准确的。 内容类型字符串将被复制到由contentType指定的缓冲区中,最多但不超过max-1个字节; 然后添加一个终止null以完成该字符串。如果成功检索到字符串并且不为空,cgiFormContentType返回 cgiFormSuccess,如果字符串成功检索, 则为空,表示没有上传任何文件或浏览器不知道内容类型,cgiFormNoContentType如果字符串被检索但被截断以适合,则 cgiFormTruncated缓冲区,如果没有提交这样的输入字段,则cgiFormNotFound。在最后一种情况下,将空字符串复制到结果。 cgiFormResultType cgiFormFileOpen(char * name,cgiFilePtr * cfpp) cgiFormFileOpen尝试为指定的类型表单字段打开实际上传的文件数据file。成功后,此函数返回用户为索引的指定格式输入字段类型声明的内容名称file。成功后,此函数将* cfpp设置为与cgiFormSuccess一起使用的有效cgiFilePtr对象。失败时,此函数将* cfpp设置为空指针,并根据需要返回cgiFormNotFound, cgiFormNotAFile, cgiFormMemory或 cgiFormIO。另请参见cgiFormFileRead 和cgiFormFileClose。 cgiFormResultType cgiFormFileRead(cgiFilePtr cfp,char * buffer,int bufferSize,int * gotP) cgiFormFileRead尝试bufferSize 从以前使用cgiFormFileOpen打开的cgiFilePtr对象读取最多字节 数。如果任何数据被成功读取,它被复制到buffer,并且成功读取的字节数被存储到*gotP。如果任何数据成功读取,此函数返回 cgiFormSuccess。在文件结束时,此函数返回cgiFormEOF。在发生I / O错误的情况下,此函数返回 cgiFormIO。如果cfp是空指针,则此函数返回cgiFormOpenFailed。另请参见cgiFormFileOpen 和cgiFormFileClose。 cgiFormResultType cgiFormFileClose(cgiFilePtr cfp) cgiFormFileClose关闭了以前使用cgiFormFileOpen打开的cgiFilePtr对象,释放内存和其他系统资源。该函数返回cgiFormSuccess 除非CFP为空,在这种情况下 cgiFormOpenFailed返回。另请参见cgiFormFileOpen 和cgiFormFileRead。 void cgiHeaderLocation(char * redirectUrl) 如果程序员希望将用户重定向到不同的URL,则应调用cgiHeaderLocation()。在这种情况下不需要更多的输出。如果你想设置cookies, 你必须对您的来电 cgiHeaderCookieSetString 和 cgiHeaderCookieSetInteger 之前调用cgiHeaderLocation。 void cgiHeaderStatus(int status,char * statusMessage) 如果程序员希望输出HTTP错误状态代码而不是文档,则应调用cgiHeaderStatus()。状态代码是第一个参数; 第二个参数是要向用户显示的状态消息。如果你想设置cookies, 你必须对您的来电 cgiHeaderCookieSetString 和 cgiHeaderCookieSetInteger 之前调用cgiHeaderStatus。 void cgiHeaderContentType(char * mimeType) 如果程序员希望根据用户的请求输出新文档,则应调用cgiHeaderContentType()。这是正常的情况。单个参数是响应的MIME文档类型; HTML文档的典型值为“text / html”,无HTML标签的普通ASCII为“text / plain”,GIF图像为“image / gif”,“.au”格式音频为“audio / basic”。如果你想设置cookies, 你必须对您的来电 cgiHeaderCookieSetString 和 cgiHeaderCookieSetInteger 之前调用cgiHeaderContentType。 void cgiHeaderCookieSetString(char * name,char * value,int secondsToLive,char * path,char * domain) 当程序员希望在用户浏览器中存储一条信息时,应调用cgiHeaderCookieSetString(),以便在对相关站点进行后续访问时再次将存储的信息提供给服务器。第一个参数是要存储的cookie的名称; 在所有浏览器中获得最佳效果,请使用无空格或不寻常标点符号的简短名称。第二个参数是要存储的cookie的值。再次,为获得最佳效果,请使用短串; 建议使用Cookie来存储唯一的标识符,然后使用该标识符来查找服务器端数据库中更详细的信息。在浏览器端存储详细信息的尝试更有可能失败。第三个参数是浏览器保存cookie的秒数; 86400是一整天,365 * 86400大概是一年。第四个参数是与其相关的网站的部分网址。/如果cookie应该发送到服务器,以便对整个站点进行访问,请将此参数设置为。最后一个参数是提交此Cookie的网站名称或整个域名; 如果您选择将cookie发送回整个域,则此参数必须以点开头,例如.boutell.com。cgic变量cgiServerName是第四个和第五个参数的方便的值。另请参见cgiHeaderCookieSetInteger,cgiCookieString,cgiCookieInteger和cgiCookies。第四个参数是与其相关的网站的部分网址。如果cookie应该发送到服务器,以便对整个站点进行访问,请将此参数设置为。最后一个参数是提交此Cookie的网站名称或整个域名; 如果您选择将cookie发送回整个域,则此参数必须以点开头,例如。cgic变量cgiServerName是第四个和第五个参数的方便的值。另请参见cgiHeaderCookieSetInteger,cgiCookieString,cgiCookieInteger和cgiCookies。第四个参数是与其相关的网站的部分网址。如果cookie应该发送到服务器,以便对整个站点进行访问,请将此参数设置为。最后一个参数是提交此Cookie的网站名称或整个域名; 如果您选择将cookie发送回整个域,则此参数必须以点开头,例如。cgic变量cgiServerName是第四个和第五个参数的方便的值。另请参见cgiHeaderCookieSetInteger,cgiCookieString,cgiCookieInteger和cgiCookies。如果cookie应该发送到服务器,以便对整个站点进行访问,请将此参数设置为。最后一个参数是提交此Cookie的网站名称或整个域名; 如果您选择将cookie发送回整个域,则此参数必须以点开头,例如。cgic变量cgiServerName是第四个和第五个参数的方便的值。另请参见cgiHeaderCookieSetInteger,cgiCookieString,cgiCookieInteger和cgiCookies。如果cookie应该发送到服务器,以便对整个站点进行访问,请将此参数设置为。最后一个参数是提交此Cookie的网站名称或整个域名; 如果您选择将cookie发送回整个域,则此参数必须以点开头,例如 。cgic变量cgiServerName是第四个和第五个参数的方便的值。另请参见cgiHeaderCookieSetInteger,cgiCookieString,cgiCookieInteger和cgiCookies。这个参数必须以一个点开头,例如。cgic变量cgiServerName是第四个和第五个参数的方便的值。另请参见cgiHeaderCookieSetInteger,cgiCookieString,cgiCookieInteger和cgiCookies。这个参数必须以一个点开头,例如。cgic变量cgiServerName是第四个和第五个参数的方便的值。另请参见cgiHeaderCookieSetInteger, cgiCookieString, cgiCookieInteger和 cgiCookies。 void cgiHeaderCookieSetInteger(char * name,int value,int secondsToLive,char * path,char * domain) cgiHeaderCookieSetInteger()与cgiHeaderCookieSetString相同 ,但要设置的值是整数而不是字符串。有关 完整信息,请参阅cgiHeaderCookieSetString。 cgiFormResultType cgiCookieString(char * name,char * result,int max) cgiFormString尝试检索为指定的cookie发送的字符串(浏览器端持久存储)。文本将被复制到由result指定的缓冲区中,最多不超过max-1个字节; 然后添加一个终止null以完成该字符串。cgiCookieString返回cgiFormSuccess如果字符串顺利取出, cgiFormTruncated如果字符串被检索,但被截断以适应缓冲区,如果字符串被检索但空无一物,cgiFormEmpty cgiFormNotFound如果没有这样的饼干已提交。在最后一种情况下,将空字符串复制到结果。 cgiFormResultType cgiCookieInteger(char * name,int * result,int defaultV) 另请参见cgiCookieInteger, cgiCookies, cgiHeaderCookieSetInteger。 cgiCookieInteger()尝试检索为指定的cookie(浏览器端持久存储)发送的整数。结果指向的值将被设置为提交的值。cgiCookieInteger()如果成功检索到该值,则返回cgiFormSuccess,如果提交的值为空字符串,则为cgiFormEmpty,如果提交的值不是整数,则为cgiFormBadType,如果未提交此类输入字段,则为cgiFormNotFound。在最后三种情况下,结果指向的值设置为指定的默认值。另请参见cgiCookieString, cgiCookies, cgiHeaderCookieSetInteger。 cgiFormResultType cgiCookies(char * name,char *** ptrToStringArray) 程序员提前不能知道所有相关的Cookie(浏览器端持久性字符串)的名称时,cgiCookie很有用。结果指向的值将被设置为指向字符串数组的指针; 数组中的最后一个条目将是空指针。该数组由CGI库分配。重要提示:使用数组时,必须使用数组指针作为参数调用cgiStringArrayFree()。cgiCookies()返回cgiFormSuccess,除非出现内存不足错误。成功时,ptrToStringArray设置为指向一个有效的字符串数组,数组中的最后一个元素是空指针; 在内存不足情况下,ptrToStringArray设置为空指针,并 返回cgiFormOutOfMemory。 cgiFormResultType cgiHtmlEscape(char * s) cgiHtmlEscape()将指定的以null结尾的字符串输出到 cgiOut,正确地遇到任何<,&和>字符,以免它们干扰HTML标记。如果发生I / O错误,返回 cgiFormSuccess或 cgiFormIO。cgiFormResultType cgiHtmlEscapeData(char * data,int len) cgiHtmlEscapeData()与cgiHtmlEscape相同,但数据不是空终止。此版本的函数输出len字节。有关 详细信息,请参阅cgiHtmlEscape。 cgiFormResultType cgiValueEscape(char * s) cgiValueEscape()将指定的以null结尾的字符串输出到 cgiOut,转义任何“正确遇到的字符,以免它们干扰HTML属性值的引号。当输入一个字符串作为输入值属性的一部分时,这很有用标签或链接或表单标签的href属性,此函数在发生I / O错误时返回 cgiFormSuccess或 cgiFormIO。cgiFormResultType cgiValueEscapeData(char * data,int len) cgiValueEscapeData()与cgiValueEscape相同,但数据不是空终止的。此版本的函数输出len字节。有关 详细信息,请参阅cgiValueEscape。 cgiEnvironmentResultType cgiWriteEnvironment(char * filename) cgiWriteEnvironment()可用于将整个CGI环境(包括表单数据)写入指定的输出文件; 然后可以使用 cgiReadEnvironment()从指定的输入文件中恢复该环境进行调试。当然,如果您使用CGI环境变量和cgiIn和 cgiOut的cgic副本而不是stdinstdout(也参见上文),这些只会按预期工作。这些功能对于在Web服务器运行时捕获真正的CGI情况是有用的,然后在调试环境中重新创建它们。这两个函数在成功时返回cgiEnvironmentSuccess,cgiEnvironmentIO上有一个I / O错误,cgiEnvironmentResultType cgiReadEnvironment(char * filename) cgiReadEnvironment()通过cgiWriteEnvironment()恢复保存到指定文件的CGI环境 。 当然,如果您使用CGI环境变量和cgiIn和 cgiOut的cgic副本而不是stdinstdout(也参见上文),这些只会按预期工作。这些功能对于在Web服务器运行时捕获真正的CGI情况是有用的,然后在调试环境中重新创建它们。这两个函数返回cgiEnvironmentSuccess成功, cgiEnvironmentIO上的I / O错误,并 cgiEnvironmentMemory 内存外的一个错误。 int cgiMain() 程序员必须编写这个函数,它执行程序的唯一任务,并由在cgic库本身中找到的true main()函数调用。来自cgiMain的返回值将是程序的返回值。预计用户将在此函数内对cgiForm函数进行大量调用。有关详细信息,请参阅如何编写cgic应用程序。cgic变量引用本节提供了由cgic提供的各种全局变量的参考指南,供程序员使用。这些变量应始终优先使用stdinstdout和调用getenv(),以确保与cgic CGI调试功能的兼容性。这些变量大多数等同于各种CGI环境变量。最重要的区别是cgic环境字符串变量永远不是空指针。他们将始终指向零个或多个字符的有效C字符串。char * cgiServerSoftware 指向服务器软件的名称,如果未知,则指向空字符串。 char * cgiServerName 指向服务器的名称,如果未知,则指向空字符串。 char * cgiGatewayInterface 指向网关界面(通常为CGI / 1.1)的名称,如果未知,则指向空字符串。 char * cgiServerProtocol 指向使用的协议(通常为HTTP / 1.0),如果未知,则指向空字符串。 char * cgiServerPort 指向服务器正在监听HTTP连接(通常为80)的端口号,或未知的空字符串。 char * cgiRequestMethod 指向请求中使用的方法(通常为GET或POST),如果未知(这不应该发生),则为空字符串)。 char * cgiPathInfo 大多数Web服务器在请求的URL中识别出超出CGI程序本身的任何附加路径信息,并将该信息传递给程序。cgiPathInfo指向这个额外的路径信息。 char * cgiPathTranslated 大多数Web服务器在请求的URL中识别出超出CGI程序本身的任何附加路径信息,并将该信息传递给程序。cgiPathTranslated指向此附加路径信息,由服务器转换为本地服务器上的文件系统路径。 char * cgiScriptName 指向调用程序的名称。 char * cgiQueryString 包含由GET方法表单或<ISINDEX>标签导致用户提交的任何查询信息。请注意,除非使用<ISINDEX>标记,否则不需要直接解析此信息; 通常它由cgic库自动解析。使用cgiForm函数系列检索与表单输入字段相关的值。请参阅如何编写一个cgic应用程序以获取更多信息。 char * cgiRemoteHost 指向浏览器的完全解析的主机名(如果已知)或空字符串(如果未知)。 char * cgiRemoteAddr 指向浏览器的点分十进制IP地址(如果已知)或空字符串(如果未知)。 char * cgiAuthType 指向用于请求的授权类型(如果有的话),如果没有或未知,则指向空字符串。 char * cgiRemoteUser 指向用户已经认证的用户名; 如果没有发生身份验证,则为空字符串。这些信息的确定性取决于使用授权的类型; 请参阅 cgiAuthType。 char * cgiRemoteIdent 由用户通过用户识别协议自愿指定用户名; 一个空字符串,如果未知。此信息不安全。识别恶魔可以由用户安装在不安全的系统,如Windows机器上。 char * cgiContentType 指向用户提交的信息的MIME内容类型(如果有); 如果没有提交信息,则为空字符串。如果此字符串等于 application/x-www-form-urlencoded或 multipart/form-data,则cgic库将自动检查提交的表单数据。如果此字符串具有任何其他非空值,则会提交不同类型的数据。这是非常罕见的,因为大多数浏览器只能直接提交表单和文件上传。 char * cgiCookie 指向Web浏览器提交的原始Cookie(浏览器端永久存储)数据。程序员应该使用函数cgiCookies, cgiCookieString和 cgiCookieInteger,而不是直接检查这个字符串。 char * cgiAccept 指向浏览器可以接受的MIME内容类型的空格分隔列表(请参阅 cgiHeaderContentType())或空字符串。不幸的是,大多数当前的浏览器并不是以一种有用的形式提供这个变量。建议希望根据浏览器功能做出决策的程序员可以根据 浏览器和功能列表检查cgiUserAgent变量。 char * cgiUserAgent 指向正在使用的浏览器的名称,如果此信息不可用,则为空字符串。 char * cgiReferrer 指向用户访问的上一页的URL。这通常是将用户带到您的程序的表单的URL。请注意,报告此信息完全取决于浏览器,可能选择不这样做,并且可能选择不这样做。但是,该变量通常是准确的。经常使用的拼错cgiReferer也作为宏提供。 int cgiContentLength 收到的表单或查询数据的字节数。请注意,如果提交是提交表单或查询,库将直接从cgiIn和/或cgiQueryString读取和解析所有信息。在这种情况下,程序员不应该这样做,实际上cgiIn指针将在文件末尾。 FILE * cgiOut 指向CGI输出。应该使用cgiHeader函数,如 cgiHeaderContentType,以输出mime头; 输出HTML页面,GIF图像或其他Web文档应该由程序员使用标准的CI / O函数(如fprintf()和fwrite())写入cgiOut。cgiOut通常相当于stdout; 但是,建议使用cgiOut来确保在特定环境下与cgic的未来版本兼容。 文件* cgiIn 指向CGI输入。在99.99%的情况下,您不需要这个。CGIC 2.0直接支持常规POST表单提交和多部分/表单数据文件上传表单提交。cgic结果代码引用在大多数情况下,即使浏览器和用户做不合理的事情,cgic功能也可以产生合理的结果。然而,有时重要的是要准确地知道哪些不合理的事情发生,特别是当分配默认值或限制值是不充分的解决方案时。以下结果代码在进行此确定时很有用。cgiFormSuccess 表示功能成功执行了至少一个操作(或在适用的情况下检索至少一个值)。 cgiFormTruncated 表示从用户检索的字符串值被缩短以避免覆盖缓冲区的结尾。 cgiFormBadType 表示用户提交的“数值”值实际上不是法定号码。 cgiFormEmpty 表示已检索到一个字段,但不包含任何数据。 cgiFormNotFound 表示没有为特定字段提交值。 cgiFormConstrained 表示数值超出了指定范围,并被适当地强制到了下限或上限。 cgiFormNoSuchChoice 表示为单选字段(如单选按钮组)提交的值不是可接受的值之一。这通常表示表单和程序之间的差异。 cgiFormEOF 在cgiFormFileRead返回 时,在调用开始时,cgiFilePtr对象已经位于上传的文件数据的末尾。 cgiFormIO 在读取上传的文件数据时发生I / O错误时由cgiFormFileRead返回。 cgiFormNotAFile 为了响应使用文件相关功能来操纵不是文件上传字段的表单域,因此返回。 cgiFormNoContentType 当浏览器未指定内容类型时,返回以回复文件上传字段的内容类型的尝试。 cgiFormNoFileName 当浏览器未指定文件名时,返回以回复文件上传字段的文件名。 cgiFormOpenFailed 返回响应尝试从空cgiFilePtr对象读取,通常当程序员未能检查对cgiFormFileOpen的调用结果时。 cgiEnvironmentMemory 表示尝试读取或写入捕获文件中的CGI环境由于内存不足错误而失败。 cgiEnvironmentSuccess 表示尝试将CGI环境读取或写入捕获文件或成功捕获文件。 cgiEnvironmentIO 表示尝试将CGI环境读取或写入捕获文件时由于I / O错误而失败。 cgiEnvironmentWrongVersion 表示尝试读取由2.0版本的CGIC生成的保存的调试CGI环境。

[原文地址,由谷歌翻译的很多代码翻译的不是很好,请查看原文][这里写链接内容](https://boutell.com/cgic/)