adnanhussainturki / unix-screen-php
Just a wrapper for Unix's screen in PHP
Requires
- illuminate/database: >=8.82
- illuminate/events: >=8.82
- nahid/jsonq: ^6.0
- symfony/process: >=5.4
README
unix-screen-php
The right-way to run shell commands or scripts right from the PHP script.
The package is exlcusively designed to be used with Laravel framework, but can also be used with Core PHP along with Laravel's Eloquent
Tutorial Playlist
Click to watch playlist on YouTube:
Installation
The package can be installed easily using Composer by executing the following command:
composer require adnanhussainturki/unix-screen-php
Prerequisite
- Create model name
Process
using commandphp artisan make:model Process
- Create a new migration using command
php artisan make:migration create_process_table
- Use the following code for migration:
Schema::create('processes', function (Blueprint $table) { $table->id(); $table->string("slug")->unique(); $table->integer("timeout")->default(30); $table->integer("exitcode")->nullable(); $table->json("data"); $table->boolean("closed")->default(false); $table->boolean("success")->nullable(); $table->dateTime("started_at"); $table->bigInteger("started_at_unix"); $table->text("remark")->nullable(); $table->timestamps(); });
Modes of execution
The package two modes of execution of commands or scripts:
-
Synchronous Good for running short time-taking commands like
ls
oruname
etc. Running the command or shell script and wait until the execution is completed. This method is NOT RECOMMENDED as it may invoke PHP timeout errors or Webserver timeout errors. Along with these, this method is not also so good for user experience. -
Asynchronous (Recommended) Great for running time-taking command or scripts like
top
orcp
ormv
etc.
Create a Screen instance
<?php
use myPHPnotes\Screen;
$screen = new Screen(storage_path("screen"), new \App\Models\Process());
Run a command asynchronously
<?php
use myPHPnotes\Screen;
$screen = new Screen(storage_path("screen"), new \App\Models\Process());
$command = "cp -r /etc/ ~/etc/";
$timeout = 30;
$arguments = [];
$identifier = "myFirstAsynchronouslyRunningCommand"; # Can be null, to use the autogenerated
$screen->executeCommand($request->command, $arguments, $identifier, $timeout);
Run a command synchronously
<?php
use myPHPnotes\Screen;
$screen = new Screen(storage_path("screen"), new \App\Models\Process());
$command = "cp -r /etc/ ~/etc/";
$timeout = 30;
$arguments = [];
$identifier = "myFirstSynchronouslyRunningCommand"; # Can be null, to use the autogenerated
$screen->executeCommandNow($request->command, $arguments, $identifier, $timeout);
Run a shell script asynchronously
<?php
use myPHPnotes\Screen;
$screen = new Screen(storage_path("screen"), new \App\Models\Process());
$script = "
echo "Welcome" $1
useradd john -m
exitcode=$? // Needs to be set to define the exit code for the whole script
touch ~/john/happy
";
// Save the script to temporary file
$filename = "shell_script_".time()."_".md5(random_bytes(1));
$temp_file_path = storage_path("screen/temp/{$filename}.sh");
file_put_contents($temp_file_path, $script);
$timeout = 30;
$arguments = ["Admin"];
$identifier = "myFirstAsynchronouslyRunningScript"; # Can be null, to use the autogenerated
$screen->executeFile($temp_file_path, $arguments, $identifier, $timeout);
Run a shell script asynchronously
<?php
use myPHPnotes\Screen;
$screen = new Screen(storage_path("screen"), new \App\Models\Process());
$script = "
echo "Welcome" $1
useradd john -m
exitcode=$? // Needs to be set to define the exit code for the whole script
touch ~/john/happy
";
// Save the script to temporary file
$filename = "shell_script_".time()."_".md5(random_bytes(1));
$temp_file_path = storage_path("screen/temp/{$filename}.sh");
file_put_contents($temp_file_path, $script);
$timeout = 30;
$arguments = ["Admin"];
$identifier = "myFirstSynchronouslyRunningScript"; # Can be null, to use the autogenerated
$screen->executeFileNow($temp_file_path, $arguments, $identifier, $timeout);
Setting up heartbeat
The heartbeat()
function Screen
object must be called every minute (or less). This heartbeat()
call will check and updates the running processes for their exit code and timeouts:
<?php
$screen = new Screen(storage_path("screen"), new \App\Models\Process());
$screen->heartbeat();
You may use the following code in your Laravel command:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Helpers\Screen;
class Heartbeat extends Command
{
protected $signature = 'screen:heartbeat';
protected $description = 'Command to check and update the status of the processes';
public function __construct()
{
parent::__construct();
}
public function handle()
{
for ($i=0; $i < 5; $i++) {
Screen::get()->heartbeat();
sleep(1);
}
return 0;
}
}
Kernel.php
$schedule->command('screen:heartbeat')->everyMinute();
Make sure to have your Laravel Task Scheduling correctly setup.
Buy me a coffee
How to contribute
-
Create a fork, make changes and send a pull request.
-
Raise a issue
License
Licensed under MIT.