Skip to content

AdnanHussainTurki/unix-screen-php

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Artboard 1

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:

IMAGE ALT TEXT HERE

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 command php 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 or uname 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 or cp or mv 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.