How to run external php-script in cake 3.7

Hi

I would like to execute a php-script in the background, because it uses about 2 minutes execution time.
I am working with Cake 3.7.

I have the following script - just for testing: (It just writes a little file with name and time)

<?php
$xfileName = date("Y-m-d H-i-s") . " Datenübername Dorothee";
$xfile = fopen("xfiles/" . $xfileName, "w+");
sleep(10);
fwrite ($xfile, $xfileName);
fclose ($xfile);
?>

In my controller I have the execution call like this:
shell_exec (‘php -f shelltest.php’);
The script is running nicely, but the view waits until it is finished.
I would like the script running in the background.

I tried like this:
shell_exec (‘php -f shelltest.php > /dev/null &’);
The script does not run at all.

I tried with exec instead of shell-exec. I didn’t help.

Do you have an idea, what I could do?
Thank you very much for your help.

Dorothee

I have used this with great success. https://github.com/dereuromark/cakephp-queue

Thank you for your advise.

For me, it sound a little bit like an overkill. Loading a huge plugin with many parameters for workers and queues. I only have a script that should run once every two or three weeks.

Or maybe I don’t understand well.
I am looking for a “submit” and “forget”.

initial answer deleted

Misunderstand the issues. What you’re saying is that 2 minutes is longer than your server script runtime?

Sorry for my bad explanation. I try again:

I have a script that needs about 2 minutes runtime. In my opinion that is too long for the user to wait and see nothig that happens. So I would like to get the script run in the background and the user could do soemthing else or at least watch a progressbar or a counter.

For testing shell_exec I made a little script that I posted before. The script just creates a file and sleeps 10 seconds. So I can check whether the script and shell_exec work the way they should.

With shell_exec (‘php -f shelltest.php’); in the controller, the script is working, but not in the background. The user has to wait until it is finished in order to see the view that belongs to the controller action.

With shell_exec (‘php -f shelltest.php > /dev/null &’); in the controller, the sript is not working.

I looked around in google and found many advises that > /dev/null & would hide the output and let the sript work in the background. It seems, that this does not work with CakePHP? Why? What is wrong?

In that case there are two possibilities: you are on a shared hoster or you run your own server.

If you’re on a dedicated server the answer is easy: create an cron job and call the script that way. That is the preferred solution.

A shared hoster usually locks down all calls like shell_exec. Trying to circumvent those is in my experience all hackery you can’t rely on, highly depend on a particular hoster and a try and error experience. Imho don’t even try to make it work, it’s wasted time. If you can’t move to a dedicated server I would create an public endpoint you call out of the PHP request. Then call that endpoint through an external services like https://www.setcronjob.com/ or async via JS from the browser client. But with that you have to take care that the public endpoint isn’t misused.

Thank you very much.
I think I try the cron job. I have at least some experiance with that.

A server job is imho the best solution if possible. PHP is a great tool implementing web based solutions, but performing out of the main request tasks isn’t its strong suit.

PS: Cake also offers facilities to write CLI helpers. [1]

[1] https://book.cakephp.org/3.0/en/console-and-shells/commands.html

In theory you could create a thread to run the process in parallel. PHP is supposed to support it:

https://www.php.net/manual/en/class.thread.php

Thanks for you giving me other solutions.

I tried with the CLI helper you promised. One should create a “Hellocommand.php”-file and put it inside the src/command-directory. In my src-directory there is no command-directory. So I created one and put the file there.
I put then the execute() statement into my controller-action, but then it says “Call to undefined function App\Controller\execute()”. I added “use Cake\Console\Command;” in my controller. That didn’t help eather.

When I put “bin/cake hello” in the PowerShell of xampp\htdocs\myapp then the command is unknown.
What is wrong? Do I have to upgrade to Cake 3.8? (I work with 3.6).

I can’t even follow the first few steps. I feel lost.

I have to admit I haven’t worked with that yet, I linked to it because it is the future proof facility. I’m still haven’t moved on from the old shell system 1 (deprecated since 3.6).

According to the documentation the new system was introduced in 3.6. That usually means that there might be bugs and the app skeleton isn’t updated, create the folder manually.

If you have a working script just run it as it is, the CakePHP shell just makes it easier if you want to access e.g. models in your script.

I’m not sure if the cake executable works like this on windows, but:

What happens if you just type

bin\cake

in your powershell? It should list all available commands, including your own.
If you command is missing there, this could have multiple reasons like

  • wrong file-permissions (Not sure how they should be on windows using xampp)
  • Error in your namespace/class declaration (had this multiple times myself)

However. If I understand correct you want to call a controller-method from inside a command - that is a little bit tricky, because you don’t have an instance of that controller while your command is being processed.
For myself I solve that problem with creating a component that holds the method-to-be-executed an then create an instance of that component like so:

// in my Shell-/Command-method
$componentRegistry = new ComponentRegistry();
$this->{"MyComponent"} = new MyComponent($componentRegistry);

// so I can do this:
$result = $this->MyComponent->myaction($args);

I solved my problem with a cronjob beause I am on a shared hoster.
It works fine, just slower than with xampp on my own machine.
For the user, I installed an ajax-request every 5 seconds to tell the amount of records the cronjob has written.
The cronjob runs every minute, but only starts really working, when the user wants that, through writing a little steering file.

Thanks for all your helping me!

Dorothee

1 Like