董老师前几天给我们布置了3道作业,第三道作业是cgi程序设计。

题目:

  web服务器cgi接口功能的实现

要求:

  能调用cgi程序并得到返回结果;

  cgi程序能接受参数并得到返回结果;

  使用两种或以上语言实现。

我的想法是:

1、既然要求能够接受参数,那么必然需要使用到表单来提交用户数据,方法可以为get或者post。

2、使用linux系统下最通用的语言——c语言,最通用的脚本语言——shell脚本。

3、该cgi程序为一个linux命令,post的数据即为该命令的参数。我选择了man命令,因为使用该命令,基本上不会产生安全隐患。不仅输入的参数具有丰富的可选项,而且不同的参数返回的结果具有很强的差异性。

一、前台html的设计

代码示例

<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>man for web</title>
<link rel="stylesheet" type="text/css" href="man.css"/> <body>
<div id="box">
<h1>man for web</h1>
<form method="get" action="/cgi-bin/man.sh" name="myform">
<input type="text" placeholder="使用shell脚本" name="cmd"></input>
<button class="but" type="submit">确定</button>
</form>
<br>
<form method="post" action="/cgi-bin/man.exe" name="myform">
<input type="text" placeholder="使用c语言" name="cmd"></input>
<button class="but" type="submit">确定</button>
</form>
</div>
</body>
</html>

  

man.css代码

html{
width: 100%;
height: 100%;
overflow: hidden;
}
body{
width: 100%;
height: 100%;
margin: 0;
background-color: #4A374A;
}
#box{
position: absolute;
top: 50%;
left:50%;
margin: -150px 0 0 -150px;
width: 300px;
height: 300px;
}
#box h1{
color: #fff;
letter-spacing: 1px;
text-align: center;
}
h1{
font-size: 2em;
margin: 0.67em 0;
}
input{
width: 278px;
height: 18px;
margin-bottom: 10px;
outline: none;
padding: 10px;
font-size: 13px;
color: #fff;
border-top: 1px solid #312E3D;
border-left: 1px solid #312E3D;
border-right: 1px solid #312E3D;
border-bottom: 1px solid #56536A;
border-radius: 4px;
background-color: #2D2D3F;
}
.but{
width: 300px;
min-height: 20px;
display: block;
background-color: #4a77d4;
border: 1px solid #3762bc;
color: #fff;
padding: 9px 14px;
font-size: 15px;
line-height: normal;
border-radius: 5px;
margin: 0;
}

  

二、cgi程序设计

  1、c语言

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 2000
main()
{
char poststr[14];
char cmd[10];
printf ("Content-type:text/plain \n\n");
int n=0;
int i;
if(getenv("CONTENT_LENGTH"))
{
n=atoi(getenv("CONTENT_LENGTH"));
fgets(poststr,n+1,stdin);
sscanf(poststr,"cmd=%s",cmd); char cmds[15];
sprintf(cmds,"man %s > data.txt",cmd);
system(cmds); FILE* fp;
int len;
if((fp=fopen("data.txt","r"))==NULL)
{
perror("fail to read");
}
while(fgets(buf,MAX_LINE,fp)!=NULL)
{
len=strlen(buf);
buf[len-1] = '\0';
printf("%s\n",buf);
}
} else{
printf("error");}
}

程序思路:

调用system函数,将处理过得post数据作为参数进行处理。

具体实现方法:  

  "Content-type:html/plain \n\n"这条语句用于输出头信息,浏览器读取到后,可获知该网页格式为plain(标准ascii字符),紧接着的两个\n\n缺一不可,否则该cgi程序不会被执行,并且访问的时候会显示500错误,查看apache2错误日志,记录为“malformed header from script. Bad header=xxx”或者“Premature end of script headers”。

  数组poststr[15]用于存储环境变量CONTENT_LENGTH,cmd[10]用于存储用户真正输入的数据,长度15够用了。cmds[15]用于存储system函数调用的程序path及参数。比如欲查询find命令相关用法,按下确定后,浏览器将使用post方法发送一串字符串到服务器,该字符串经过url编码,编码后的字符串为“cmd=find”。在这个案例中,数组poststr的作用就是存储这个字符串,数组cmd的作用是存储"find",数组cmds的作用是存储“man find > in.txt”,至于怎么通过poststr来生成cmd、cmds,则需要用到相应的函数。

  if(getenv("CONTENT_LENGTH")用于判断传递的字符串是否为空。

  语句 fgets(poststr,n+1,stdin) 作用是从标准输入中读取n个字符串并存储到数组poststr[]。参考百度百科:“从文件结构体指针stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋'\0')”,函数原型:char *fgets(char *buf, int bufsize, FILE *stream)。

  语句 sscanf(poststr,"cmd=%s",cmd) 作用是生成cmd字符串。参考百度百科:“sscanf() - 从一个字符串中读进与指定格式相符的数据”。通俗的理解就是裁剪字符串,提取有效信息。

  语句 sprintf(cmds,"man %s > data.txt",cmd) 作用是将字符串cmd和“man ”拼接,生成字符串cmds。

  c语言中,system()函数用于调用系统命令。比如system("ls")调用ls命令,然而system调用成功返回值是0,因此需要将结果重定向到一个文本文件中再读取此文本文档以显示命令执行结果。system(cmds)相当于system("man xxx")。

  之后的语句用于打开文本文档,不再详细解释。

  2、使用shell脚本

#!/bin/bash
echo "content-type:text/html"
echo
echo "<html>"
echo "<head>"
echo "<meta charset="UTF-8">"
echo "<title>shell-cgi实现man命令</title>"
echo "<style>"
echo "pre {margin:0 auto; width:"50%"; height:"100%"; font-size:12pt;}"
echo "</style>"
echo "</head>"
echo "<body>"
echo "<pre>"
data=$QUERY_STRING
cmd=${data#*cmd=}
if man $cmd >/dev/null;then
man $cmd
else
echo "没有查询到相关信息"
echo "</pre>"
echo "</body>"
echo "</html>"

  data=$QUERY_STRING用于从环境变量中获取数据并赋给data。

  cmd=${data#*cmd=} 作用是从data字符串中截取“cmd=”之后的字符串。

  之所以使用<pre>标签是因为位如果不使用的话生成的html页面不自动换行。 

ps.不需要担心不怀好意的人输入一下诸如 "ls && rm -rf / "之类的数据到cgi,因为数据的传输都是经过了url编码的,空格会变成加号,特殊字符也会改变。shell.cgi没有进行相应的解码,输入多个命令传递给cgi程序的只是一堆无意义的乱码,如果设计成对url完全解码的cgi程序,应该格外注意安全问题。

利用cgi编程实现web版man手册的更多相关文章

  1. shell脚本作为cgi程序--以web版man为例

    man.cgi源码 #! /bin/sh eval `sh proccgi.sh $*` echo "Content-type: text/html" echo echo echo ...

  2. Web 版 PowerDesigner (Canvas) 技术

    什么是 Canvas?    HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像. 画布是一个矩形区域,您可以控制其每一像素. canvas 拥有多种绘制路径.矩形.圆形. ...

  3. Python的Web编程[1] -> Web服务器[0] -> Web 服务器与 CGI / WSGI

    Web服务器 / Web Server 对于Web来说,需要建立一个Web服务器,必须建立一个基本的服务器和一个处理程序, 基本服务器的主要作用是,在客户端和服务器端完成必要的HTTP交互, 处理程序 ...

  4. Kali Linux Web渗透测试手册(第二版) - 1.3 - 靶机的安装

    Kali Linux Web渗透测试手册(第二版) - 1.3 - 靶机的安装  一.配置KALI Linux和渗透测试环境 在这一章,我们将覆盖以下内容: 在Windows和Linux上安装Virt ...

  5. JAVA面向对象编程课程设计——web版斗地主

    一.团队课程设计博客链接 JAVA面向对象编程课程设计--网络版单机斗地主 二.个人负责模块或任务说明 实体类的设计 斗地主规则的实现 人机自动出牌的算法 实现数据库的DAO模式 三.自己的代码提交记 ...

  6. CGI编程完全手册

    一.基本原理 CGI:通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口.通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器 ...

  7. 物联网网络编程、Web编程综述

    本文是基于嵌入式物联网研发工程师的视觉对网络编程和web编程进行阐述.对于专注J2EE后端服务开发的童鞋们来说,这篇文章可能稍显简单.但是网络编程和web编程对于绝大部分嵌入式物联网工程师来说是一块真 ...

  8. Python学习笔记-CGI编程(如何在IIS上挂Python开发的Webservice)

    一.如何用Python开发一个简单的Webservice 利用python的cgi编程,可以传入参数将结果输出. 定义需要编码以及需要引用的模块 #conding=utf-8 #修正中文乱码 impo ...

  9. (笔记)Linux下的简单CGI编程

    为什么要进行CGI编程?  在HTML中,当客户填写了表单,并按下了发送(submit)按钮后,表单的内容被发送到了服务器端,一般的,这时就需要有一个服务器端脚本来对表单的内容进行一些处理,或者是把它 ...

随机推荐

  1. Elasticsearch集群管理工具head插件安装

    Elasticsearch-head是一个elasticsearch的集群管理工具,它是完全由html5编写的独立网页程序,你可以通过插件把它集成到es.或直接下载源码,在本地打开index.html ...

  2. Linux之HugePages快速配置

    关于Linux系统的HugePages与Oracle数据库优化,可以参考熊爷之前的文章,相关概念介绍的非常清晰: Linux大内存页Oracle数据库优化 本文旨在Linux系统上快速配置HugePa ...

  3. node.js初识04

    node的Get表单提交 form.html <!DOCTYPE html> <html lang="en"> <head> <meta ...

  4. equals和==的区别小结

    ==: == 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象.比较的是真正意义上的指针操作. 1.比较的是操作符两端的操作数是否是同一个对象 ...

  5. mysql 5.6 每天凌晨12:00 重置sequence表中的某个值

    #.创建evevt要调用的存储过程update_current_value_procedure delimiter // drop procedure if exists update_current ...

  6. Android -- 仿淘宝广告条滚动

    1,在赶项目的时候我们经常会实现下面这个功能,及添加滚动条广告广播,先看一下淘宝的效果 2,这次实现效果主要使用Android自带的ViewFlipper控件,先来看一下我们的它的基本属性和基本方法吧 ...

  7. Unity之fragment shader中如何获得视口空间中的坐标

    2种方法: 1. 使用 VPOS 或 WPOS语义,如: Shader "Test/ScreenPos1" { SubShader { Pass { CGPROGRAM #prag ...

  8. python base64加密文本内容(1)

    仅仅使用base64加密安全系数太低了,我们还可以自定义base64加密后的文本进行一些变化,提高安全系数,在解密时再回复某些变化 1,先实现一个base64加密 import base64 impo ...

  9. Spark学习之路 (十一)SparkCore的调优之Spark内存模型

    摘抄自:https://www.ibm.com/developerworks/cn/analytics/library/ba-cn-apache-spark-memory-management/ind ...

  10. webpack4.0 实战记录

    从零配置webpack4.0 搭建React工程. 基本环境:Node(v8.1.2)+ webpack(v4.16.2) 1.在项目目录 命令窗口  执行  npm init 初始化项目,执行完后项 ...