通过ajax运行php脚本,但前提是尚未运行 [英] Running a php script via ajax, but only if it is not already running

查看:93
本文介绍了通过ajax运行php脚本,但前提是尚未运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的意图是这个.

我的client.html通过ajax调用php脚本check.php.我要check.php检查是否另一个脚本task.php已经在运行.如果是这样,我什么也不做.如果不是,则需要在后台运行.

My client.html calls a php script check.php via ajax. I want check.php to check if another script task.php is already being run. If it is, I do nothing. If it is not, I need to run it in the background.

我知道我想做什么,但是不确定如何做.

I have an idea what I want to do, but am unsure how to do it.

A部分.我知道如何通过Ajax调用check.php.

Part A. I know how to call check.php via ajax.

B部分.在check.php中,我可能需要运行task.php.我想我需要像这样的东西:

Part B. In check.php I might need to run task.php. I think I need something like:

$PID = shell_exec("php task.php > /dev/null & echo $!");

我认为>/dev/null&"位告诉它在后台运行,但是不确定"$!"是什么.会.

I think the "> /dev/null &" bit tells it to run in the background, but am unsure what the "$!" does.

C部分.我需要$ PID作为过程的标记.我需要将此编号(或其他编号)写入同一目录中的文件,并且每次对check.php的调用都需要读取该编号.我不知道该怎么做.有人可以给我一个链接,告诉您如何在同一目录中读取/写入具有单个数字的文件吗?

Part C. The $PID I need as a tag of the process. I need to write this number (or whatever) to a file in the same directory, and need to read it every call to check.php. I can't work out how to do that. Could someone give me a link of how to read/write a file with a single number in to the same directory?

D部分.然后检查上次启动的task.php是否仍在运行,我将使用以下功能:

Part D. Then to check if the last launched task.php is still running I am going to use the function:

function is_process_running($PID)
{
   exec("ps $PID", $ProcessState);
   return(count($ProcessState) >= 2);
}

我认为这就是我所需要的全部内容,但是如您所见,我不确定如何执行其中的一些操作.

I think that is all the bits I need, but as you can see I am unsure on how to do a few of them.

推荐答案

我会使用

I would use an flock() based mechanism to make sure that task.php runs only once.

使用这样的代码:

<?php

$fd = fopen('lock.file', 'w+');

// try to get an exclusive lock. LOCK_NB let the operation not blocking
// if a process instance is already running. In this case, the else 
// block will being entered.
if(flock($fd, LOCK_EX | LOCK_NB )) {
    // run your code
    sleep(10);
    // ...
    flock($fd, LOCK_UN);
} else {
    echo 'already running';
}

fclose($fd);

还要注意,正如PHP文档指出的那样,flock()可在所有支持的操作系统上移植.

Also note that flock() is, as the PHP documentation points out, portable across all supported operating systems.

!$

为您提供bash中最后执行的程序的pid.像这样:

gives you the pid of the last executed program in bash. Like this:

command &
pid=$!
echo pid

请注意,您必须确保您的php代码在具有bash支持的系统上运行. (不是Windows)

Note that you will have to make sure your php code runs on a system with bash support. (Not windows)

更新(在开启者的评论之后).

Update (after comment of opener).

flock()将在所有操作系统上运行(如上所述).我在使用Windows的代码中看到的问题是!$(正如我提到的;)..

flock() will work on all operating systems (As I mentioned). The problem I see in your code when working with windows is the !$ (As I mentioned ;) ..

要获取task.php的pid,您应该使用 以启动task.php.我准备了两个示例脚本:

To obtain the pid of the task.php you should use proc_open() to start task.php. I've prepared two example scripts:

task.php

$fd = fopen('lock.file', 'w+');

// try to get an exclusive lock. LOCK_NB let the operation not blocking
// if a process instance is already running. In this case, the else 
// block will being entered.
if(flock($fd, LOCK_EX | LOCK_NB )) {
    // your task's code comes here
    sleep(10);
    // ...
    flock($fd, LOCK_UN);
    echo 'success';
    $exitcode = 0;
} else {
    echo 'already running';
    // return 2 to let check.php know about that
    // task.php is already running
    $exitcode = 2; 
}

fclose($fd);

exit($exitcode);

check.php

$cmd = 'php task.php';
$descriptorspec = array(
   0 => array('pipe', 'r'),  // STDIN 
   1 => array('pipe', 'w'),  // STDOUT
   2 => array('pipe', 'w')   // STDERR
);

$pipes = array(); // will be set by proc_open()

// start task.php
$process = proc_open($cmd, $descriptorspec, $pipes);

if(!is_resource($process)) {
    die('failed to start task.php');
}

// get output (stdout and stderr)
$output = stream_get_contents($pipes[1]);
$errors = stream_get_contents($pipes[2]);

do {
    // get the pid of the child process and it's exit code
    $status = proc_get_status($process);
} while($status['running'] !== FALSE);

// close the process
proc_close($process);

// get pid and exitcode
$pid = $status['pid'];
$exitcode = $status['exitcode'];

// handle exit code
switch($exitcode) {
    case 0:
        echo 'Task.php has been executed with PID: ' . $pid
           . '. The output was: ' . $output;
        break;
    case 1:
        echo 'Task.php has been executed with errors: ' . $output;
        break;
    case 2:
        echo 'Cannot execute task.php. Another instance is running';
        break;
    default:
        echo 'Unknown error: ' . $stdout;
}

您问我为什么我的flock()解决方案是最好的.仅仅是因为另一个答案不能可靠地确保task.php运行一次.这是因为我在该答案下方的评论中提到的比赛条件.

You asked me why my flock() solution is the best. It's just because the other answer will not reliably make sure that task.php runs once. This is because the race condition I've mentioned in the comments below that answer.

这篇关于通过ajax运行php脚本,但前提是尚未运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆