使用C语言来写网页

Posted on Mon, 12 Jul 2010 11:59:59 -1100

前面的几篇文章简单介绍了一些基础知识,

本文给出一个具体的实例,

先说明一下

测试环境是xampp套件(apache)+win32

开发工具是SlickEdit+Mingw

 

下面的文字主要介绍,用C语言[CGI]捕获html表单传递的信息.

其实和PHP,PERL类似,简单的方法就是环境变量的获取

[常用的环境变量,我前面的文章已经罗列了一些,这里就不多说了]

在C语言中,环境变量需要通过

	char *  getenv (const char *)

这个函数来获取,使用时需要包含stdlib.h这个头文件

有了这个函数,其它的就很简单了,写一个html的表单,比如

	<form name="input" action="../cgi-bin/test.exe" method="post">
Username: 
<input type="text" name="user" />
<input type="submit" value="Submit" />
</form>

注意 : action指向所需可执行文件[win下自然是exe了,linux下管用.cgi的后缀]

当然还有一个前提,就是Apache的CGI功能必须打开,这个配置很简单的,过阵子有空了再总结,这里不多罗嗦.

如果我们,输入了一些字符,点击提交后[假设那个test.exe里面用getenv捕获了某个环境变量,并打印出来],

会发现和我们想象的有些差异,

这里简单说明一下,

        1.最常见的疑问是html中的转义字符串,命令行中的\n或是\n\r到html里就应该用</br>,类似的还有一些

        2.如果我们输入的有空格,那么返回时编程了'+'号

        3.如果我们输入一个中文词组[假定GB2132编码]--"你好",那么返回的是 "%C4%E3%BA%C3"

        4.其它没有总结的......(哈哈)

1的话自己注意下就好,2和3可以写一个简单的函数避免这些问题,比如像下面这样

void   decode(unsigned char *src , unsigned char *dst)
{
	unsigned int len=0;
	unsigned int i=0,j=0;

	len=strlen(src);
	while (i<len) {
		if (*(src+i) == '+') {
			*(dst+j) = ' ';
		} else if (*(src+i) == '%') {
			unsigned int code;    
			if (sscanf(src+i+1,"%2x",(unsigned int *)&code)!=1) {
				code=(unsigned int)'?';
			}
			*(dst+j)=(unsigned char)code;
			i+=2; 
		} else{
			*(dst+j)=*(src+i);
		}
		++i;
		++j;
	} 
	*(dst+j)='\0';  
}    

啰嗦的就到这里,下面给出完整的测试用例[关于环境变量的意义,见我前文的总结]

#include<stdio.h>
#include<stdlib.h>    
 
void   decode(unsigned char *src , unsigned char *dst)
{
	unsigned int len=0;
	unsigned int i=0,j=0;

	len=strlen(src);
	while (i<len) {
		if (*(src+i) == '+') {
			*(dst+j) = ' ';
		} else if (*(src+i) == '%') {
			unsigned int code;    
			if (sscanf(src+i+1,"%2x",(unsigned int *)&code)!=1) {
				code=(unsigned int)'?';
			}
			*(dst+j)=(unsigned char)code;
			i+=2; 
		} else{
			*(dst+j)=*(src+i);
		}
		++i;
		++j;
	} 
	*(dst+j)='\0';  
}    



int   main()    
{    
	unsigned char *env;

	long len;

	printf("%s\n\n", "Content-Type:text/html;charset=gb2312");


	env=getenv("CONTENT_LENGTH");
	printf("CONTENT_LENGTH : %s</br>",env);

	env=getenv("DOCUMENT_ROOT");
	printf("DOCUMENT_ROOT : %s</br>",env);

	env=getenv("HTTP_REFERER");
	printf("HTTP_REFERER : %s</br>",env);

	env=getenv("HTTP_USER_AGENT");
	printf("HTTP_USER_AGENT : %s</br>",env);

	env=getenv("PATH_INFO");
	printf("PATH_INFO : %s</br>",env);

	env=getenv("PATH_TRANSLATED");
	printf("PATH_TRANSLATED : %s</br>",env);

	env=getenv("QUERY_STRING");
	printf("QUERY_STRING : %s</br>",env);

	env=getenv("REMOTE_ADDR");
	printf("REMOTE_ADDR : %s</br>",env);

	env=getenv("REMOTE_ADDR");
	printf("REMOTE_ADDR : %s</br>",env);

	env=getenv("REMOTE_HOST");
	printf("REMOTE_HOST : %s</br>",env);

	env=getenv("REQUEST_METHOD");
	printf("REQUEST_METHOD : %s</br>",env);

	env=getenv("SCRIPT_NAME");
	printf("SCRIPT_NAME : %s</br>",env);

	env=getenv("REQUEST_URI");
	printf("REQUEST_URI : %s</br>",env);

	env=getenv("SERVER_NAME");
	printf("SERVER_NAME : %s</br>",env);

	env=getenv("SERVER_PORT");
	printf("SERVER_PORT : %s</br>",env);

	unsigned char oriData[500];
	unsigned char data[500];
	fgets(oriData,500,stdin);
	printf("original data : %s , %d</br>",oriData,strlen(oriData)  );
	decode(oriData,data);
	printf("data : %s , %d</br>",data,strlen(data)  );

	return   0;    
}    

对应的html表单的代码前面贴过了,就不重复贴了,

假设我们在表单中填上"你好"这个词组,那么当我们点击提交按钮后,

如果配置正确的话,浏览器会像我们返回类似如下的字串,

CONTENT_LENGTH : 17
DOCUMENT_ROOT : E:/xampp/htdocs
HTTP_REFERER : http://localhost/test.html
HTTP_USER_AGENT : Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6
PATH_INFO : (null)
PATH_TRANSLATED : (null)
QUERY_STRING :
REMOTE_ADDR : 127.0.0.1
REMOTE_ADDR : 127.0.0.1
REMOTE_HOST : (null)
REQUEST_METHOD : POST
SCRIPT_NAME : /cgi-bin/test2.exe
REQUEST_URI : /cgi-bin/test2.exe
SERVER_NAME : localhost
SERVER_PORT : 80
original data : user=%C4%E3%BA%C3 , 17
data : user=你好 , 9

HTTP报文实例

Posted on Mon, 12 Jul 2010 00:43:03 -1100

本文整理自网络,原始链接不知何处........

 

在罗列具体的实例之前,先啰嗦几句概念性的东西.

GET,POST,SOAP都是基于HTTP协议的,但是,

POST 是被设计用来向上放东西的,而GET是被设计用来从服务器取东西的,

GET也能够向服务器传送较少的数据,而Get之所以也能传送数据,

只是用来设计告诉 服务器,你到底需要什么样的数据.

POST的信息作为HTTP 请求的内容,而GET是在HTTP 头部传输的.

当然数据传送量上,POST自然要多些...

SOAP是依赖于HTTP POST模式实现的,它遵循一种特殊的xml消息格式
在SOAP中,Content-type设置为: text/xml,任何数据都可以xml化

具体看以下HTTP的格式

发送

<request line>

<headers>

<blank line>

[<request-body>]

接收

<status line>

<headers>

<blank line>

[<response-body>]

在响应中唯一真正的区别在于第一行中用状态信息代替了请求信息。状态行(status line)通过提供一个状态码来说明所请求的资源情况。

而常用的状态码如下

◆200 (OK): 找到了该资源,并且一切正常。
◆304 (NOT MODIFIED): 该资源在上次请求之后没有任何修改。这通常用于浏览器的缓存机制。
◆401 (UNAUTHORIZED): 客户端无权访问该资源。这通常会使得浏览器要求用户输入用户名和密码,以登录到服务器。
◆403 (FORBIDDEN): 客户端未能获得授权。这通常是在401之后输入了不正确的用户名或密码。
◆404 (NOT FOUND): 在指定的位置不存在所申请的资源。

 

 

下面仅是HTTP中最常用的GET和POST方法几个实例,以及基于POST的SOAP方法

GET 方法

发送:

GET /DEMOWebServices2.8/Service.asmx/CancelOrder?UserID=string&PWD=string&OrderConfirmation=string HTTP/1.1
Host: api.efxnow.com

接收:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<objPlaceOrderResponse xmlns="https://api.efxnow.com/webservices2.3">
<Success>boolean</Success>
<ErrorDescription>string</ErrorDescription>
<ErrorNumber>int</ErrorNumber>
<CustomerOrderReference>long</CustomerOrderReference>
<OrderConfirmation>string</OrderConfirmation>
<CustomerDealRef>string</CustomerDealRef>
</objPlaceOrderResponse>

注意其中没有实质的内容,自然也没有CONTENT-LENGTH,所以在CGI中若是GET方法发送的报文,通过环境变量获得的值为NULL

特别要注意其中的空行,之前是报文头,之后是报文的实际内容,下面的POST方法,发送时也有类似的规则

POST方法

发送

POST /DEMOWebServices2.8/Service.asmx/CancelOrder HTTP/1.1
Host: api.efxnow.com
Content-Type: application/x-www-form-urlencoded
Content-Length: length

UserID=string&PWD=string&OrderConfirmation=string

接收

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<objPlaceOrderResponse xmlns="https://api.efxnow.com/webservices2.3">
<Success>boolean</Success>
<ErrorDescription>string</ErrorDescription>
<ErrorNumber>int</ErrorNumber>
<CustomerOrderReference>long</CustomerOrderReference>
<OrderConfirmation>string</OrderConfirmation>
<CustomerDealRef>string</CustomerDealRef>
</objPlaceOrderResponse>

最后再介绍一种基于POST的方法

SOAP方法(soap 1.2)

发送

POST /DEMOWebServices2.8/Service.asmx HTTP/1.1
Host: api.efxnow.com
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
    <CancelOrder xmlns="https://api.efxnow.com/webservices2.3">
      <UserID>string</UserID>
      <PWD>string</PWD>
      <OrderConfirmation>string</OrderConfirmation>
    </CancelOrder>
</soap12:Body>
</soap12:Envelope>

回复

HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
    <CancelOrderResponse xmlns="https://api.efxnow.com/webservices2.3">
      <CancelOrderResult>
        <Success>boolean</Success>
        <ErrorDescription>string</ErrorDescription>
        <ErrorNumber>int</ErrorNumber>
        <CustomerOrderReference>long</CustomerOrderReference>
        <OrderConfirmation>string</OrderConfirmation>
        <CustomerDealRef>string</CustomerDealRef>
      </CancelOrderResult>
    </CancelOrderResponse>
</soap12:Body>
</soap12:Envelope>          

 

另外要补充说明的是,上面例子中报文头部分都比较简单,还有一些特别的属性可以根据需要添加,

比如要求服务器自动断开链接等功能就可以通过一些属性来设置

再举两个例子

GET发送

GET /books/?name=Professional%20Ajax HTTP/1.1
Host: www.wrox.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Connection: Keep-Alive

POST发送

POST / HTTP/1.1
Host: www.wrox.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
Connection: Keep-Alive
     (----此处空一行----)
name=Professional%20Ajax&publisher=Wiley

CGI中常用的环境变量

Posted on Sun, 11 Jul 2010 13:20:58 -1100

简单总结一下CGI中常用的环境变量,

当然我本初学,有一些也没用过,有一些仅是网上资料的汇总.

另外只是概要性的叙述,有一些变量在某些时候会返回空值,具体情况并未一一列出.

 

CGI中常用的环境变量

1. CONTENT_LENGTH

2. DOCUMENT_ROOT

3. HTTP_REFERER

4. HTTP_USER_AGENT

5. PATH_INFO

6. PATH_TRANSLATED

7. QUERY_STRING

8. REMOTE_ADDR

9. REMOTE_HOST

10. REQUEST_METHOD

11. SCRIPT_NAME

12. REQUEST_URI

13. SERVER_NAME

14. SERVER_PORT

概要1. 获取POST方法中传递实际信息的有效字节数
(CONTENT_LENGTH)

概要2. www目录信息获取
(DOCUMENT_ROOT)

概要3. 链接到当前页面的前一页面的 URL 地址。不是所有的用户代理(浏览器)都会设置这个变量,而

且有的还可以手工修改它。
因此,这个变量不总是真实正确的。
(HTTP_REFERER)

概要4. 客户端的名称和版本号
(HTTP_USER_AGENT)

概要5. http://www.test.com/index.php/foo/bar.html?c=index&m=search
我们可以得到 $_SERVER['PATH_INFO'] = ‘/foo/bar.html’,而此时 $_SERVER['QUERY_STRING'] =

'c=index&m=search';
(PATH_INFO)

概要6. 获取本文件的绝对路径
(PATH_TRANSLATED)

概要7. 获取IP地址
(REMOTE_ADDR)

概要8. 获取hostname
(REMOTE_HOST)

概要9. 获取请求方法,一般为GET,POST,HEAD
(REQUEST_METHOD)

概要10. # http://www.yoursite.com/example/  -- -- -- /
# http://www.yoursite.com/example/index.php -- -- -- /example/index.php
# http://www.yoursite.com/example/index.php?a=test -- -- -- /example/index.php?a=test
# http://www.yoursite.com/example/index.php/dir/test -- -- -- /example/index.php/dir/test
(REQUEST_URI)

概要11. # http://www.yoursite.com/example/  -- -- -- /example/index.php
# http://www.yoursite.com/example/index.php -- -- -- /example/index.php
# http://www.yoursite.com/example/index.php?a=test -- -- -- /example/index.php
# http://www.yoursite.com/example/index.php/dir/test -- -- -- /example/index.php
(SCRIPT_NAME)

概要12. 服务器的hostname或IP
(SERVER_NAME)

概要13. 服务器的监听端口
(SERVER_PORT)

概要14. http://www.test.com/index.php/foo/bar.html?c=index&m=search
我们可以得到 $_SERVER['PATH_INFO'] = ‘/foo/bar.html’,而此时 $_SERVER['QUERY_STRING'] =

'c=index&m=search';
注意:QUERY_STRING只是用于GET方法.
(QUERY_STRING)