Skip to main content
 首页 » 编程设计

php之运行PHP代码而无需等待Python返回值

2024年10月01日26lautakyan007

我有一个运行python脚本的PHP脚本,

exec("C:/Python26/python C:/xampp/htdocs/timeout.py"); 


效果很好。但是Python代码会在10分钟内返回一个值。我想在5分钟内在浏览器 echo "Time out";上显示,而无需等待返回值。

firstpg.php

<form action="spg.php" method="POST" enctype="multipart/form-data"> 
<div align="center"><input type="submit"name="submit" value="INSERT">  
    <input type="submit" name="show" value="Show"> 
</div> 
</form> 


secondpg.php

<?php 
 
$start_time = time(); 
$timeVar=true; 
 
while(true) { 
 
    if ((time() - $start_time) < 300) { 
 
        $read= exec("start C:/Python26/python C:/xampp/htdocs/test/timeout.py"); 
    } 
    else 
    { 
        echo "Time out"; 
    } 
}    
?> 


超时时间

from multiprocessing  
import Process 
import time  
 
def do_actions():     
    i = 0 
    while True: 
        i += 1 
        # print(i) 
        time.sleep(1)  
 
if __name__ == '__main__': 
    # We create a Process 
    action_process = Process(target=do_actions) 
 
    # We start the process and we block for 5 seconds. 
    action_process.start() 
    action_process.join(timeout=600) 
 
    # We terminate the process. 
    action_process.terminate() 
    print("Hey there! I timed out! You can do things after me!") 

请您参考如下方法:

介绍

您的代码以及用于执行此操作的方法有很多问题。我将尝试尽可能简单地回答它,但是请记住,这不是一个简单的问题-它可能需要一些解释。



您的代码存在的问题

首先,为什么您现有的解决方案不起作用?我马上注意到的一些事情是:


while(true)循环是无限的。由于您永远不会break退出,因此该代码将永远无法完成执行。您可能打算将$timeVar用作while循环的条件,并在代码中进行更改,但从未这样做。
在每个循环中,如果经过了不到300秒,您将尝试通过再次执行Python脚本来再次读取其输出。您在这里忘记的是exec()是一个阻止函数-这意味着它执行完之后什么都不会执行-因此您只需要在这里等待脚本的整个执行-通过放下任何内容都不会真正改变它在循环中。


当然,这些都是可以理解的错误。这是一个难题。



exec()功能

许多此类问题似乎归结为exec(),该函数用于执行命令行语句,在执行任何其他代码之前等待语句完成。这样做的原因是命令的实际工作方式-如果需要打印错误或输出命令,则需要分别打印到stderr和stdout。在PHP中,exec()充当stderr和stdout,因此命令需要能够在此处发送输出。这意味着直到命令完成,PHP才能继续运行。

如果您使用的是* nix系统,这会容易得多。但是,在Windows上,我们将不得不放弃使用exec(),而是使用两个不同的功能:popen()和pclose()。

首先,我们需要使该命令在后台运行。这是一个非常简单的任务:在命令的开头,您已编写start,我们将改为编写start \b(从后台开始)。

可是等等!如果命令的结果始终在后台运行,我们将如何获得该命令的结果?这是重定向运算符>>出现的地方。它将所有输出从Shell函数发送到文件中。因为我们使用了两个>字符,所以它将覆盖那里已经存在的任何文件。这将在以后变得很重要。

因此,在您的test目录(包含PHP和Python脚本)中创建一个文件夹,并将其命名为output。然后,我们将为PHP中的文件生成一个名称,以便多个人可以一次使用您的网站,而不会得到彼此的输出。我们可以仅使用time()函数-它们不太可能都在完全相同的时间执行。现在,您应该能够将输出发送到output目录中的文件,该文件将以当前time()值命名。

现在来谈谈难点:执行它。 popen()运行命令。它的第一个参数是命令,第二个是其模式。它返回一个资源指针。您可以在下面链接的PHP手册上阅读有关此内容的信息。我们需要知道的是,在"r"模式下,如果发生错误(还会包含任何Shell错误消息),它也会返回资源,因此它运行命令并始终返回我们需要关闭的指针。

从而:

$filename = time().".txt"; 
pclose(popen("start \b C:/Python26/python C:/xampp/htdocs/test/timeout.py >> \"C:/xampp/htdocs/test/output/$filename\"", "r")); 


应该在后台运行我们的命令。

关于此主题的进一步阅读:


php exec command (or similar) to not wait for result
How To Redirect Command Prompt Output to a File
exec on the PHP manual
popen on the PHP manual




整理secondpg.php

现在,我们在后台运行您的Python脚本。我们的PHP文件可以结束并向用户显示页面,并且Python仍将在服务器上运行。但是我们将如何获得输出?

首先,我们需要记住文件名-将其存储在会话cookie中应该可以很好地工作。在secondpg.php的最顶部,我们需要添加代码 session_start(),以便我们可以使用会话cookie。然后,通过使用会话超级全局变量 $_SESSION["filename"] = $filename;进行设置,将文件名存储在cookie中。

我们需要做的另一件事是确保文件存在,以便我们以后可以检查它是否为空( >>将使用Python脚本的输出覆盖它,但仅在脚本完成之后)。我们可以使用 file_put_contents()创建文件。

我们还需要包含一个JavaScript文件(尚未编写)。因此,这是secondpg.php:

<?php 
session_start(); //Allows us to use sessions 
 
$time = time(); //Creates a filename using the current time past the epoc as a unique identifier 
 
file_put_contents("output/$time",""); //Ensure that the file exists, and is empty 
 
$_SESSION["time"] = $time; //Sets the filename in a session cookie, so we can use it later 
 
pclose(popen("start \b C:/Python26/python C:/xampp/htdocs/test/timeout.py >> \"C:/xampp/htdocs/test/output/$time.txt\"", "r")); //Runs our Python script 
?> 
<script src="check.js"></script> 


进一步阅读:


PHP sessions


获取输出

现在,您需要编写一个新的PHP文件。称之为get_output.php。该代码非常基本:

<?php 
session_start(); //Allows us to use sessions 
 
if (time()-$_SESSION["time"]>300) { //If the file was made more than 300 seconds (five minutes ago) we just echo timeout 
    echo "Timeout"; 
} 
else { 
    echo file_get_contents("output/".$_SESSION["time"].".txt"); //Echo out the contents of the file. Pulls the filename out of our session cookie. 
} 
?> 


希望该文件是不言自明的:它只是 echo清除输出文件的内容。

现在,我们需要编写一个JavaScript文件。这将在用户计算机上运行,​​并且每五秒钟将运行我们刚刚编写的PHP文件,以便我们可以检查文件是否包含内容。它将内容写入页面正文。

将此文件称为check.js:

function do_check() { 
    var http = new XMLHttpRequest(); //Open a request to another page 
    http.onreadystatechange = function() { 
        if (http.readyState==4&&http.status==200) { //If we have loaded the page successfully 
            document.body.innerHTML = http.responseText; //Set the body content to be the response text 
        } 
    } 
    http.open("GET","get_output.php",true); //Request the file 
    http.send(); //Send the request 
} 
 
setInterval("do_check()", 5000); //Call the function every five seconds. 


进一步阅读:


JavaScript XMLHttpRequest


结论

那应该就是您所需要的。每五秒钟,页面内容将更改为文件内容,您可以自己更改文件来进行检查-页面应该更新以显示更改。