这几天在做的一个系统中,需要给指定的用户发送email,由于对方只提供了可执行程序,所以需要在CGI中调用。
虽然之前就知道可以通过system()或者popen()来实现,但是在真正用在CGI场景中的时候还是吃了不少苦头。
先来看一下system(),函数声明如下:
int system(const char *command);
入参就是需要执行的命令,函数会返回成功或者失败。
这个函数有两个问题:
1.函数调用的时候会fork进程,对于有些webserver是禁止fork的。(我一开始在CGI调用全是返回-1,即fork失败)
2.命令执行时,如果有向标准输出打印,不会被重定向。即,在CGI中使用的杯具就是,会直接将打印信息返回给浏览器
对于第二条,假设我直接将输出重定向的结果会怎样呢,比如执行命令"ps -ef > x",实际上,在apache中执行的话,apache还是一样能拿到输出。由于我是在http header之前输出,所以报了这样的错误。
目前我的解决办法是用popen,函数声明如下:
FILE *popen(const char *command, const char *type);
用popen("mailsend dantezhu"),命令内部的输出就会被重定向。
由于对于发送email这个命令本身我是不关心其成功与否的,所以并没有对其返回值做任何检查。
另外还有一点比较让人困惑,在apache下,我用CGI直接输出301跳转是会失败的,出错信息如下:
原来的输出方式是:
#define MMANCGI_REDIRECT(ret)
{
char url[100];
if(ret)
snprintf(url,sizeof(url),"http://mman.qq.com/mman_error.html?ret=%d",ret);
else
snprintf(url,sizeof(url),"http://mman.qq.com/mman_succ.html");
printf("HTTP/1.1 301 Moved Permanently\r\n");
printf("Connection: close\r\n");
printf("Content-Type: text/html\r\n");
printf("Location: %s\r\n\r\n", url);
return ret;
};
后来改成:
int Output(ret)
{
char url[100];
if(ret)
snprintf(url,sizeof(url),"http://mman.qq.com/mman_error.html?ret=%d",ret);
else
snprintf(url,sizeof(url),"http://mman.qq.com/mman_succ.html");
PrintHttpHeader();
cout <<
"<script type=\"text/javascript\">document.domain=\"mman.qq.com\";location=\"" << url << "\";</script>";
return ret;
};
就没有问题了,应该是apache对支持301跳转需要额外的模块,由于任务在身,所以也就没有时间深究了。
OK,就这样吧~
依云 on #
那个 301,不需要前面的 HTTP/1.1 的,直接 301 (message)。
另外,使用 HTML 的 meta 标签也可以实现跳转。
那个 system 重定向为什么不行呢?我在 linux 下的测试成功(ls > b,错误日志显示 sh 尝试创建文件 b 被 Permission denied 了。
Reply
Dante on #
哦哦,我回公司试一下。
那个创建文件禁止,会不会你的apache启动用户没有apache bin目录的写权限呢?
Reply
依云 on #
很明显我没有给它写权限。我的意思是,在Linux上在system里重定向是可行的。我很奇怪在Windows上为什么不行,难道Win下没有把命令交给cmd而是直接执行的?
Reply
Dante on #
我在win下面没测试过……,应该都是调用的外部命令吧,你不是不小心在win下面用ls吧……
Reply