0

I have a long task for a slim controller, I would like to early end the output to client and then continue the backend elaboration.

$app->get("/test",function() use($app){
    $app->render("page.html"); //this is the client output
    $app->easlyStop(); //a slim hypothetical command to call
    $task=new MyTask();
    $task->longAsyncTask(); //this take a few, client don't have to wait.
});

Is there a solution with Slim?

Tobia
  • 9,165
  • 28
  • 114
  • 219
  • Output is a final stage of script execution. – u_mulder Sep 18 '17 at 13:43
  • Possible duplicate of [Asynchronous PHP calls?](https://stackoverflow.com/questions/124462/asynchronous-php-calls) – OptimusCrime Sep 18 '17 at 13:45
  • Did you try to google "PHP async method"? – OptimusCrime Sep 18 '17 at 13:45
  • 1
    I'm looking for a Slim solution, the solution should be integrated or a plugin of this framework. So I have to exclude all exec(), ob_clean solutions. – Tobia Sep 18 '17 at 13:57
  • Slim is just a request/response based micro framework. How you solve this problem does not depend on the framework. That is the whole point of using a micro framework to begin with. – OptimusCrime Sep 18 '17 at 14:06
  • if this works: https://stackoverflow.com/a/14469376/861646 I think it is possibile to add a slim plugin to do what I'm looking for. – Tobia Sep 18 '17 at 14:29

2 Answers2

0

The easiest option here is to call a method with a system call and return before it finishes:

exec('/bin/php /path/to/a/script.php > /dev/null &');

Note that this is a simplification as PHP is request oriented, which means that a new process is started for every request, and the webserver sends the response to the user once the request is finished. You could use flush and other techniques, but these are prone to errors and depends on the configurations of the webserver too.

OptimusCrime
  • 14,662
  • 13
  • 58
  • 96
0

This is a method for Slim controller with Json view:

$app->get( '/test/', function () use($app) {
        $app->view = new Json();
        try{
            //here the output of Json view
            $model=["myjsondata"=>[]];
            $app->render(200,$model);
        }catch (\Slim\Exception\Stop $e) {}

        //following code is copied from Slim->run() to early output
        $app->response()->headers->replace(["Content-Length"=>$app->response()->length()]);
        $app->response()->headers->replace(["Connection"=>"close"]);
        list($status, $headers, $body) = $app->response->finalize();
        \Slim\Http\Util::serializeCookies($headers, $app->response->cookies, $app->settings);
        if (headers_sent() === false) {
            if (strpos(PHP_SAPI, 'cgi') === 0) {
                header(sprintf('Status: %s', \Slim\Http\Response::getMessageForCode($status)));
            } else {
                header(sprintf('HTTP/%s %s', $app->config('http.version'), \Slim\Http\Response::getMessageForCode($status)));
            }
            foreach ($headers as $name => $value) {
                $hValues = explode("\n", $value);
                foreach ($hValues as $hVal) {
                    header("$name: $hVal", false);
                }
            }
        }
        if (!$app->request->isHead()) {
            echo $body;
        }

        //early output to client
        ob_end_flush();
        ob_flush();
        flush();
        if (session_id()) session_write_close();

        //my async job
        sleep(5);
    });

I think this can be easily insert in a Slim plugin. This works only with Json view becase this is my need but it can be used with Twig or other Slim views getting output with ob* php functions instead of catching the Stop() exception.

Tobia
  • 9,165
  • 28
  • 114
  • 219