lighttpd с "php fastcgi" отправляет вывод на консоль вместо браузера - PullRequest
1 голос
/ 20 июня 2011

У меня есть php-скрипт, работающий в качестве сервера fastcgi, который выполняет запрошенные браузером php-файлы (почему бы не использовать php / php-cgi? Из-за проблемы с производительностью , мы тоже использовали APC, но все еще недостаточно хороши):

# cat myphpcgi
#!/usr/local/php5/bin/php

<?php

while (Accept() >= 0) {     # simple wrapper of FCGI_Accept from FastCGI dev-kit
    $file = GetRequestFile();   # get requested .php file name(like /var/www/htdocs/a.php)
    if ($file == FALSE)
    continue;
    $contents = file_get_contents($file);
    if ($contents == FALSE)
        continue;
    # remove heading <?php and trailing ?>
    $contents = ltrim($contents);
    $contents = rtrim($contents);
    $start = strpos($contents, "<?php");
    $start += 5;
    $end = strrpos($contents, "?>");
    $end -= 2;
    $ct = substr($contents, $start, $end);
    # execute the requested file
    eval($ct);
}

?>

При использовании вышеуказанного скрипта cgi библиотеки функций / классов будут загружены только один раз (с помощью require_once).

Сценарий запускается с помощью:

# /usr/local/lighttpd/bin/spawn-fcgi -f /var/www/cgi-bin/myphpcgi -a 127.0.0.1 -p 8888

И lighttpd настроен так: ...

fastcgi.server = ( ".php" =>
                    ("localhost" =>
                      ( "host" => "127.0.0.1",
                        "port" => 8888,
                      )
                    )
                 )

...

Нокогда браузер запрашивает a.php, как показано ниже:

<?php
require_once "bigfunction.php"
echo "haha";
printf("hehe");
?>

Сценарий cgi выводит «hahahehe» на системную консоль, а не в браузер.

# hahahehe

Если я обертываю FCGI_printfфункция (из FastCGI devkit тоже) и использовать ее для распечатки строк, результат будет отправлен в браузер, это решение, но существующий код должен будет внести изменения.

Я также протестировал сApache и вывод просто идет в apache error_log.Возможно, dup2 () решит проблему, но я не нашел fd, который использует FastCGI devkit.

PS __autoload не сэкономит наше время, так как большинство включений - это функции и константы.

PS2 dup2 () не решит проблему: из вывода strace скрипта cgi:

write(1, "haha", 4haha)                     = 4
write(1, "hehe\n", 5hehe)                   = 5
write(3, "\1\6\0\1\0\0\0\0\1\3\0\1\0\10\0\0\0\0\0\0\0\0\0\0", 24) = 24
shutdown(3, 1 /* send */)  

, где fd 3 - соединение с lighttpd, когда я добавил dup2 (3, 1),получил ошибку 500 в браузере, и журнал lighttpd показывает:

2011-05-24 13:09:54: (mod_fastcgi.c.2443) unexpected end-of-file (perhaps the fastcgi process died): pid: 0 socket: tcp:127.0.0.1:8888
2011-05-24 13:09:54: (mod_fastcgi.c.3237) response not received, request sent: 834 on socket: tcp:127.0.0.1:8888 for /large.php , closing connection

PS3: код для Accept ():

PHP_FUNCTION(Accept)
{
    int n = FCGI_Accept();
    RETVAL_LONG(n);
    return;
}

код для GetRequestFile ():

PHP_FUNCTION(GetRequestFile)
{
    char buf[1024];
    char *p = NULL;
    int ret;

    // apache and lighttpd has different name
    p = getenv("PATH_TRANSLATED");
    if (p == NULL) {
        p = getenv("SCRIPT_FILENAME");
        if (p == NULL) {
            RETVAL_BOOL(0);
            return;
        }
    }

    memcpy(buf, p, strlen(p));
    buf[strlen(p)] = '\0';
    RETVAL_STRINGL(buf, strlen(buf), 1);
    //dup2(3, 1);
    return;
}

PS4 Когда добавляется оболочка для FCGI_printf, как показано ниже:

PHP_FUNCTION(Myprintf)
{
    char *str;
    int str_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
        return;
    }

    char *p = emalloc(str_len + 1);
    memcpy(p, str, str_len);
    p[str_len] = '\0';
    FCGI_printf("%s", p);
    efree(p);
    return;
}

Использование Myprintf () для печати строк, когда myphpcgi работает вместе с apache, работает нормально, и строка отображается в браузере.Но при использовании lighttpd строка никуда не денется, интересно ...

Ответы [ 2 ]

0 голосов
/ 23 июня 2011

@ hakre Наконец, эта проблема решена путем взлома phpsrc / sapi / cgi / cgi_main.c.Причина в том, что поведение php echo и printf контролируется разными sapis, такими как cgi, cli, sapi определяет, где находится пункт назначения.Модули не могут изменить пункт назначения.

В cgi_main.c исходный рабочий процесс выглядит так:

listen();
while (req = accept()) {
    php_request_start();
    php_execute_script();
    php_request_shutdown();
}

Все, что я сделал, это переместил начало и завершение запроса из цикла while,

listen();
php_request_start();
while (req = accept()) {
    php_execute_script();
}
php_request_shutdown();

Работает нормально, и "require_onced-files" будет загружен только один раз.

0 голосов
/ 20 июня 2011

Вам не нужно самим писать обертку FCGI, чтобы предлагать FCGI для PHP.

Вместо этого вам следует использовать существующую обертку для выполнения сценариев PHP как FCGI.Он работает с любым существующим кодом PHP.


Вместо eval просто включите файл:

# remove heading <?php and trailing ?>
include($file);

Возможно, это гарантирует, что require_once будет работать должным образом.

...