5

我有一个问题,我在页面加载时调用 PHP 函数 - 该函数检查文件是否存在,它返回文件名,如果不存在,它运行一个相当足智多谋且需要时间的脚本 - 转换波形图像从音频文件。问题是音频文件很大,因此创建文件可能需要一些时间,因此如果音频文件没有与之关联的图像文件,则页面加载所需的时间与该过程一样长。

我所追求的是这个函数返回一个占位符图像(如果不存在),但在页面加载后继续该过程 - 或在后台。所以理论上,当页面在以后重新加载时,正确的图像就会在那里。

我目前可以获得占位符图像的返回,但随后该过程停止并且图像不会生成。这是我到目前为止所拥有的:

function example($file_path, $file_name) {if ($file_path) {

if (file_exists("/path/to/folder/{$file_name}.png")) {
  return "/path/to/folder/{$file_name}.png";
}
if (!file_exists("/path/to/folder/{$audio_file_name}.png")) {

  return "/path/to/folder/processing.png";      

Some stuff in here

 return $new image

} return FALSE

正如你所看到的,当文件不存在时,这只是停止,但我希望这里的东西在后台继续。有可能还是我需要不同的方法?像 cron 工作之类的?任何帮助表示赞赏。

4

5 回答 5

3

您可以尝试像 resque https://github.com/chrisboulton/php-resque这样的排队系统

然后,您可以生成一个作业,处理信息并使用“处理”图像快速返回。使用这种方法,您将不知道它何时完成。

以我的经验,这仍然比与操作人员争论使用多线程支持编译 php 更容易。

于 2013-02-14T23:46:00.513 回答
2

如果您在 FastCGI / FPM 上运行,您可以考虑执行以下操作:

  1. 您放置了一个常规<img>标签,其src属性指向您的脚本。

  2. 如果您的脚本需要重新生成,您可以让浏览器重定向到正在处理的图像。

  3. 如果图像准备好,您将重定向到创建的图像(您也可以在页面上进行 AJAX 轮询)

第2步怎么做?

通常,浏览器在执行渲染或重定向之前必须等待您的脚本结束;但是 FastCGI (PHP-FPM) 对此有一个特殊的功能:fastcgi_finish_request. 它在很大程度上没有记录,但它的使用很简单:

if ($need_to_process) {
    header('Location: /path/to/processing.png');
    fastcgi_finish_request();
    // do processing here
} else {
    header('Location: /path/to/final_image.png');
}

选择

如果您有一个可以在执行之前立即渲染的模板,您也可以将它应用到您现有的流程中fastcgi_finish_request()

还有另一种选择

使用像 Gearman 这样的任务调度程序。

于 2013-02-14T23:58:44.617 回答
1

我会用 AJAX 来做。如果找到图像,只需将其放在那里。

否则,放置占位符,并添加带有数据的JS标志以加载波形图像。

在生成 HTML 文档的 PHP 代码中,不会发生转换。你有另一个请求处理程序来处理来自 JS 的请求,它使用提供的数据进行转换。

最初在 HTML 文档生成代码上创建的数据将被传递给 JS,JS 将使用它来发送转换请求。当 JS 等待响应时,您处理加载时间,当响应到来时,您将其放在占位符上。

于 2013-02-15T00:07:02.943 回答
0

我无法发表评论,因为我的声誉低于 50,但我想在 mohammadhasan 的回答中指出一些内容。它似乎有效,但在 try 和 finally 块中都避免了“return”语句

try {
    return "hello world";
} finally {
    //do not put return here
}

例子:

function runner() {
    try {
        return "I am the trial runner";
    } finally {
        return "I am the default runner";
    }
}

echo runner();

只会显示I am the default runner

于 2019-12-16T08:35:57.720 回答
0

你可以使用“try”和“finally”

try {
    return "hello world";
} finally {
    //do something
}
于 2019-06-28T11:34:13.053 回答