在nginx上运行cgi程序

我们用到的很多开源程序比如mailman, nagios等等,都有WEB端管理界面。在那个Apache一家独大的年代,这个问题可以很好解决,因为apache本身可以运行cgi程序。但随着nginx服务器的大规模应用,而恰好nginx又没有cgi模块,所以我们不得不采用一些变通的手段来解决它。

在网上广为流传的解决方法是一个老外写的perl脚本,但这个脚本本身有很多问题,而且需要在后台启动一个守护进程,本人对用perl写的网络服务守护进程的稳定性很怀疑,在看了它的代码后,发现用PHP即可很好的解决这个问题。

首先我们要明白的是CGI其实本质上就是一个普通的二进制程序,你可以在后台直接运行它。而服务器要做的事就是将WEB传递的变量作为参数传递给这个程序并执行,而将执行返回的结果显示到页面上。

明白了这个道理,我们就可以开始着手解决这个问题了。其过程无非就是将PHP作为一个proxy,使其运行指定的程序,并把程序输出结果echo出来。

那么首先第一步,我们就需要把原来的cgi请求全部转发到指定的php上,这一点在nginx里用rewrite就可以很简单的做到。我们把这个PHP脚本命名为cgi.php,把它随便放到一个你认为合适的位置,然后用rewrite将后缀为cgi的请求都转发到cgi.php上。以下为参考的配置格式

#rewrite cgi请求到cgi.php上,并把cgi文件名作为php的pathinfo rewrite ^/nagios/cgi-bin/(.*) /cgi.php/$1 break; location /nagios/ { gzip off; alias /usr/local/nagios/share/; index index.html index.htm index.php; } location ~ .*\.php(\/.*)*$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fcgi.conf; fastcgi_param SCRIPT_FILENAME /usr/local/nagios/share$fastcgi_script_name; #pathinfo必须设置 fastcgi_param PATH_INFO $fastcgi_script_name; #以下两个为cgi.php需要用到的变量名,分别为cgi程序目录,和cgi默认index程序 fastcgi_param CGI_BASE /usr/local/nagios/sbin; fastcgi_param CGI_INDEX status.cgi; }

这是nagios的配置文件。
注意上面配置文件的注释部分,在你自己设置的时候必须填上合适的值。下面就是最重要的cgi.php文件了

0) { $cgi_path = $cgi_path . '/' . array_shift($cgi_file_levels); if (is_file($cgi_path)) { $cgi_file_exists = true; break; } } if (!$cgi_file_exists) { die('NOT EXISTS PAGE!' . $cgi_file); } $cgi_pathinfo = ''; if (!empty($cgi_file_levels)) { $cgi_pathinfo = '/' . implode('/', $cgi_file_levels); } if (is_readable($cgi_path)) { $descriptorspec = array( 0 => array("pipe", "r"), // stdin is a pipe that the child will read from 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 2 => array("file", "/tmp/error-output.txt", "a") // stderr is a file to write to ); $cwd = $cgi_base; $env = $_ENV; $env['SCRIPT_FILENAME'] = $cgi_path; $env['SCRIPT_NAME'] = $cgi_file; $env['DOCUMENT_ROOT'] = CGI_BASE; $env['PATH_INFO'] = $cgi_pathinfo; // http auth support (nagios etc.) if (isset($_SERVER['PHP_AUTH_USER'])) { $env['REMOTE_USER'] = $_SERVER['PHP_AUTH_USER']; } $process = proc_open($cgi_path, $descriptorspec, $pipes, $cwd, $env); if (is_resource($process)) { $stdin = file_get_contents("php://input"); if (!empty($stdin)) { fwrite($pipes[0], $stdin); fclose($pipes[0]); } //stream_set_blocking($pipes[1], 0); stream_set_timeout($pipes[1], 3); $result = stream_get_contents($pipes[1]); fclose($pipes[1]); $return_value = proc_close($process); list($header, $body) = preg_split("/\r?\n\r?\n/", $result, 2); $headers = explode("\n", $header); foreach ($headers as $line) { header(trim($line)); } echo $body; } else { die('ERROR APPLICATION!'); } } else { die('ERROR PAGE!' . $cgi_path); }

你也可以访问我的google code主页获取最新的的代码
http://code.google.com/p/joyqi/source/browse/trunk/php/cgi.php

已有 13 条评论

  1. 呜啦 呜啦

    特地来学习、膜拜下

  2. minah minah

    特来学习。

  3. Xiao怪兽 Xiao怪兽

    你好站长,问您一个Typecho的问题
    我在write-post.php把原来的文本框改为了kindeditor编辑框,但这样一来自动保存功能竟不能使用了,希望站长在闲时能帮我一下这个问题.谢谢你啦!

  4. 湖南SEO 湖南SEO

    牛人噢。 我想深入学习php,所以在研究typecho。能否指点下我怎么去深入学习php? 我还是个学生。如果您有时间的话,期待您加我QQ 245291359聊。

  5. fox fox

    回楼上
    About里有70的联系方式,你用不着留QQ啊

  6. riophae riophae

    额.. Typecho 现在算是暂停开发了么.. 好久没动静了..

  7. Change Change

    你好站长,我想询问下关于Typecho在Nginx上运行的问题,
    我装的LNMP上默认不支持Typecho的伪静态,我自己加个规则之后后台就无法登陆,我在Typecho官方讨论区上看到解决方法,可是那上面的location.conf和我的配置不一样,我是个新手,麻烦你指教下,我的location.conf配置是:

    location ~* .*\.php($|/)
    {
          if ($request_filename ~* .*\.php$) {
             set $is_path_info '0';
          }
          if (-e $request_filename) {
             set $is_path_info '1';
          }
          if ($is_path_info ~ '0') {
             return 403;
          }
    
        fastcgi_pass  127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
        }
    
    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
        {
            expires      30d;
        }
    
    location ~ .*\.(js|css)?$
        {
            expires      12h;
        }
    1. 混蛋70 混蛋70

      @Change
      你可以在这里找到答案
      http://docs.typecho.org/servers#无法实现伪静态化_在后台设置不成功

  8. 萝卜 萝卜

    好精简的页面

  9. 阿飞 阿飞

    哥们,你的RSS好像没法订阅。

  10. 子曰关注 子曰关注

    话说 apache没有nginx的并发高,但是apache还是比较好配置的

  11. willy willy

    原理的确是这样的,不知道你写这篇文章的时候有没有php-fpm,
    fpm使用fast-cgi的形式,这个可以很好的解决cgi的问题

  12. yaya yaya

    可以试试nginx+spawn-fcgi而不用通过php

添加新评论