如何让脚本在后台运行 - 不工作

时间:2016-07-10 10:07:12

标签: php filepath popen ratchet pclose

我正在尝试启动Ratchet的chat-server.php文件,该文件是从php文件启动套接字服务器所需的,这样每当客户端访问该页面时,服务器就会启动,但它不会发生。这个chat-server.php文件需要从终端运行,但我试图在用户访问的主页面上运行它。

文件结构

  

./的index.php

     

./ config.php中

     

./ vendor /(所有供应商文件)

     

./ SRC / MyApp的/ Chat.php

     

./ JS / app.js

     

./ inc / connect.php< - 数据库连接文件

     

./ inc / send-message.php

     

./ inc / startServer.php

     

./ INC / bg.php

     

./ INC / serverStatus.txt

     

./ css / index.css

     

./ CSS / reset.css

     

./斌/聊天server.php

的config.php

<?php
    include_once ("./inc/startServer.php");
?>

聊天server.php

<?php

    use Ratchet\Server\IoServer;
    use Ratchet\Http\HttpServer;
    use Ratchet\WebSocket\WsServer;
    use MyApp\Chat;


    if(isset($startNow)){ 

            require dirname(__DIR__) . '/vendor/autoload.php';

            $server = IoServer::factory(
                new HttpServer(
                    new WsServer(
                        new Chat()
                    )
                ),
                8080
            );

            $server->run();

    }

?>

bg.php

<?php
    $startNow = 1;
    include_once ("../bin/chat-server.php");
?>

startServer.php

<?php

$statusFile = dirname(__FILE__).'/serverStatus.txt';
$status = file_get_contents($statusFile);
if($status == "0"){

        function execInBackground($cmd) {
                if(substr(php_uname(), 0, 7) == "WINDOWS") {
                    pclose(popen('start /B ' . $cmd, 'r'));
                    file_put_contents($statusFile, 1);
                }
                else {
                    exec($cmd . ' > /dev/null &');
                    file_put_contents($statusFile, 1);
                }
        }

        execInBackground("php " . dirname(__FILE__) . "/bg.php");

}

&GT;

serverStatus.txt

其默认值已设为 0

注意:相应地更新了代码,但现在仍无法使用。

加号我不知道在所有客户离开时重新启动服务器,或者如何关闭服务器。

2 个答案:

答案 0 :(得分:1)

当您使用相对路径包含文件时,您必须记住它们与当前正在运行文件相关,而不仅仅是当前档案

在你的情况下。当您访问index.php并在其中加入config.php以及从startServer.php开始时,一切正常,因为您包含的./inc/startServer.php相对于{{index.php 1}}。
但是你要包括../inc/serverStatus.txt,这是不对的,因为你仍然在运行index.php并且相对路径解析为/../inc/serverStatus.txt,换句话说你正在尝试访问一个文件等级高于DOCUMENT_ROOT。因此,您永远不会进入if声明 您可以使用__FILE__常量,该常量始终解析为<​​strong>当前文件的绝对路径。因此,您可以将$statusFile更改为

$statusFile = dirname(__FILE__) . '/serverStatus.txt';

接下来是关于exec()popen(pclose())命令的问题。如果要执行某个不在PATH环境变量中的命令,则必须指定文件的绝对路径。因为您不知道它将从哪个文件夹启动。它可以从Apache家庭目录开始,也可以从用户的家庭目录开始。这取决于PHPsapi模块的设置还是fcgi。无论如何,您需要将execInBackground()更改为

execInBackground("php " . dirname(__FILE__) . "/bg.php");

在命令中添加一些空格,如下所示:

pclose(popen('start /B ' . $cmd, 'r'));
exec($cmd . ' > /dev/null &');
这样你就不会有一些可能发生的奇怪错误。

bg.php 中,您需要更改当前的工作目录,如下所示:

<?php
    $startNow = 1;
    chdir(dirname(__FILE__));
    include_once ("../bin/chat-server.php");
?>

这样,PHP无论您从哪个文件夹运行都会找到chat-server.php

顺便说一句,您是如何计划停止服务器的? =)

更新:您的函数execInBackground()中也存在变量范围问题。您的函数依赖于变量$statusFile,但此变量在全局范围中定义,并且在函数内部不可见。要使其可见,您必须在访问global $statusFile;之前在函数中包含语句$statusFile。像这样:

    function execInBackground($cmd) {
            global $statusFile;
            if (false !== stripos(PHP_OS, 'win')) {
                pclose(popen('start /B ' . $cmd, 'r'));
                file_put_contents($statusFile, 1);
            } else {
                exec($cmd . ' > /dev/null &');
                file_put_contents($statusFile, 1);
            }
    }

我改变了您检查操作系统的方式,因为您的方法包含错误。

<强> UPDATE2

经过一系列的测试,我发现当php脚本在后台运行时(在Windows下),它无法使用&#34; echo()&#34;写到STDOUT。当它发生时,php脚本将默默地死亡,没有错误。因此,请将所有echo()更改为某个日志功能。

将侦听端口更改为其他一些,这是免费的,例如50000.因为,8080通常可能已被某些Web服务器或其他服务使用。

请记住!只有拥有自己的服务器(如VPS / VDS或专用服务器),才能启动聊天服务器公共主机出于安全原因,没有人允许您为传入连接打开某个端口。在公共服务器上,由于相同的原因,通常会禁用exec()popen()等类似的功能。

答案 1 :(得分:0)

我认为你应该阅读http://php.net/manual/es/function.shell-exec.php

请注意,当PHP以安全模式运行时,此功能被禁用。