什么是cgi

cgi是 common gateway interface的简称,这是一个用来处理http请求的接口;
由于http请求十分多样且十分复杂,web服务器不能完成这种操作,于是便利用了外部程序来处理这些请求,web服务器将参数传递给外部程序,外部程序将运行结果返回给web服务器;外部程序和web服务器的交互需要一种接口,那就是cgi接口,于是这些外部程序也叫cgi程序;
cgi程序不是某种语言的产物,而是一种接口,你既可以用c语言来实现cgi程序也可以用php,甚至是shell脚本来实现;
关系图如下:

外部程序是如何与web服务器进行交互的

cgi提供两种传递参数的方式:标准输入输出流,环境变量
这里的环境变量不同于操作系统提供的环境变量,这是web服务器和cgi接口所提供的用以向cgi程序传递一些重要的参数如(客户机的ip-$REMOTE-ADDR);
html中的post请求方法是用标准输入(stdin)来向cgi程序传递参数的,而html中的get请求方法则是通过环境变量QUERY-STRING来传递参数的;
下面是一些常见的cgi环境变量:
变量名描述
CONTENT_TYPE这个环境变量的值指示所传递来的信息的MIME类型。目前,环境变量CONTENT_TYPE一般都是:application/x-www-form-urlencoded,他表示数据来自于HTML表单。
CONTENT_LENGTH如果服务器与CGI程序信息的传递方式是POST,这个环境变量即使从标准输入STDIN中可以读到的有效数据的字节数。这个环境变量在读取所输入的数据时必须使用。
HTTP_COOKIE客户机内的 COOKIE 内容。
HTTP_USER_AGENT提供包含了版本数或其他专有数据的客户浏览器信息。
PATH_INFO这个环境变量的值表示紧接在CGI程序名之后的其他路径信息。它常常作为CGI程序的参数出现。
QUERY_STRING如果服务器与CGI程序信息的传递方式是GET,这个环境变量的值即使所传递的信息。这个信息经跟在CGI程序名的后面,两者中间用一个问号'?'分隔。
REMOTE_ADDR这个环境变量的值是发送请求的客户机的IP地址,例如上面的192.168.1.67。这个值总是存在的。而且它是Web客户机需要提供给Web服务器的唯一标识,可以在CGI程序中用它来区分不同的Web客户机。
REMOTE_HOST这个环境变量的值包含发送CGI请求的客户机的主机名。如果不支持你想查询,则无需定义此环境变量。
REQUEST_METHOD提供脚本被调用的方法。对于使用 HTTP/1.0 协议的脚本,仅 GET 和 POST 有意义。
SCRIPT_FILENAMECGI脚本的完整路径
SCRIPT_NAMECGI脚本的的名称
SERVER_NAME这是你的 WEB 服务器的主机名、别名或IP地址。
SERVER_SOFTWARE这个环境变量的值包含了调用CGI程序的HTTP服务器的名称和版本号。例如,上面的值为Apache/2.2.14(Unix)

一个shell脚本写的cgi程序例子;

这个例子会用到上面写的内容,同时也有一些对shell脚本语法的解析

#!/bin/sh

echo "Content-type: text/plain"
echo ""

if [ "$REQUEST_METHOD" = "GET" ] ; then		#用POST的请求方式
	echo GET is not expected without https
	exit                     
fi

echo "<html><head>"
echo "</head><body>"
echo "<pre>"


ip=$REMOTE_ADDR					#通过环境变量将客户机ip赋给ip变量

OIFS="$IFS"
IFS=\&                  			#域分割符,作用请参考这篇博客:<a target=_blank href="http://http://blog.csdn.net/occupy8/article/details/38386985">点击打开链接</a>
read user passwd inout  			# 从标准输入(stdin)中读取POST过来的字段;post方式传递参数的实例
IFS="$OIFS"

user=${user#username=}        			# 把开始的前缀'username='去掉(变量$user中是“username=具体名字”要将$user中的“username=”去掉,再赋给user
passwd=${passwd#password=}    
inout=${inout#inout=}         

echo "user, passwd and your ip is: $user $passwd $ip"


userconf='/etc/nasuser.list'    		# 用grep命令判断传递进来的参数在nasuser.list文件中‘|’是ubuntu中的管道命令作用是将结果传递给下一条指令;
grepstr="grep $userconf -e $user | grep $passwd" #grep是查找命令;这句话的作用是:从nasuser.list文件中找出变量$user所在的那一行,传递给grep $password;
							#这条命令再从结果中查找$password;
userline=`$grepstr`
if [ -z "$userline" ] ; then         		#-z	判断$userline时候为空;不为空则说明传进来的用户和密码是正确的可以登录;
	echo "invalid user"   
    exit
fi

echo ok
echo ""     # 
#exit


if [ ${ip:4:1}  == ":" ] ; then   		# 构造ip6tables命令 
iptcmd1="/sbin/ip6tables -D FORWARD  -s $ip/128 -j ACCEPT"
iptcmd2="/sbin/ip6tables -I FORWARD  -s $ip/128 -j ACCEPT"
iptcmd3="/sbin/ip6tables -D FORWARD  -d $ip/128 -j ACCEPT"
iptcmd4="/sbin/ip6tables -I FORWARD  -d $ip/128 -j ACCEPT"
else
						# 构造iptables命令
iptcmd1="/sbin/iptables -t nat -D PREROUTING -s $ip/32 -j ACCEPT"
iptcmd2="/sbin/iptables -t nat -I PREROUTING -s $ip/32 -j ACCEPT"
iptcmd3="/sbin/iptables -t filter -D FORWARD -s $ip/32 -o enp0s3 -j ACCEPT"
iptcmd4="/sbin/iptables -t filter -I FORWARD -s $ip/32 -o enp0s3 -j ACCEPT"
fi

echo 'before: ipv4'
/sbin/iptables --list -n | grep all
/sbin/iptables --list -n -t nat | grep all

echo 'before: ipv6'
/sbin/ip6tables --list -n | grep all
/sbin/ip6tables --list -n -t nat | grep all

echo ""
echo "action:"
echo $iptcmd1
res=`$iptcmd1`
echo $iptcmd3
res=`$iptcmd3`
if [ $inout == "I" ] ; then
echo $iptcmd2
res=`$iptcmd2`
echo $iptcmd4
res=`$iptcmd4`
fi

echo ""
echo 'after: ipv4'
/sbin/iptables --list -n | grep all
/sbin/iptables --list -n -t nat | grep all

echo 'after: ipv6'
/sbin/ip6tables --list -n | grep all
/sbin/ip6tables --list -n -t nat | grep all

#cat /etc/nasuser.list

echo "</pre>"

if [ $inout == "I" ] ; then
echo "<font color=red> <strong>如果出现某些可能的BUG,请关闭浏览器窗口并重新打开即可。</strong>"
fi

echo "</body></html>"

exit


参考了以下两篇博客
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐