PHP Plumber.

You need a wesbite. You have a website. Why not ceate your own ?

PHP is known as a language to create a Website. Despite of this, PHP can served as multiporpuse script. For historical reason. BASH evolve to Perl, Perl Evolve to PHP. Since we have similar behaviour borrowed form the predecessor, it would not be so difficult to include PHP in this Tutorial group.

In fact this PHP script version is very similar with Lua script version.

Goal: A script that continuously show date and time, with Dzen2, and Conky.

Before you dip your toe to scripting, you might desire to know the reason by reading this overview.

Reading


Piping and Forking in Many Languages

This article is one part of a collection. All integrated, on related to another. So we can compare each other quickly.

Tutorial/ Guidance/ Article: [ Pipe Overview ] [ BASH ] [ Perl ] [ Python ] [ Ruby ] [ PHP ] [ Lua ] [ Haskell ]

Source Code Directory: [ BASH ] [ Perl ] [ Python ] [ Ruby ] [ PHP ] [ Lua ] [ Haskell ]


Compatibility

For accounting reason in my company. I’m still using PHP56 in my notebook. You are free to switch the #shebang to PHP7.

Do not worry, I do not use any sophisticated code.


Start Simple

Welcome to n00berland. Begin with simple script. We will use this loop as a source feed to pipe. This step won’t introduce Pipe nor Fork.

This script only show an infinite loop showing local time. Each updated in one second interval. We manage this interval by delaying, using sleep code.

Source:

#!/usr/bin/php56  
<?php 

$timeformat = '%a %b %d %H:%M:%S';

do {
    print strftime($timeformat)."\n";
    sleep(1);
} while (true);

Call to this simple code would produce time marching, one after another, below the command line prompt.

Pipe: Basic

Similar Code: [ BASH basic ] [ Perl basic ] [ Python basic datetime ] [ Python basic time ] [ Ruby basic ] [ PHP basic ] [ Lua basic ] [ Haskell basic ]


External Command as Source Feed

Beside previous simple loop that is used as Internal Command, this tutorial also provide Conky as External Command in asset directory. I made it as simple as possible.

Source:

conky.config = {
    out_to_x = false,
    out_to_console = true,
    short_units = true,
    update_interval = 1
}

conky.text = [[\
${time %a %b %d %H:%M:%S}\
]]

A Unidirectional Pipe Between External Command

This step is overview of Pipe between two external command. Instead of system command, this utilize popen using two handles: pipein and pipeout.

This is a very simple. Just a few self explanatory lines. This very short script is using conky as pipe source feed and less as pipe target. Showing time and date forever in the console.

This infinite pipe run in time-less fashioned.

I add _ dir _, relative to the PHP source, to locate the conky script assets.

Source:

#!/usr/bin/php56  
<?php 

# http://php.net/manual/en/function.popen.php

$path    = __dir__."/../assets";
$cmdin   = 'conky -c '.$path.'/conky.lua';
$cmdout  = 'less'; # or 'dzen2'

# handle
$pipein  = popen($cmdin,  "r");
$pipeout = popen($cmdout, "w");

while(!feof($pipein)) {
    $buffer = fgets($pipein);
    fwrite($pipeout, $buffer);
    flush();
}

pclose($pipein);
pclose($pipeout);

You can see, how simple it is. This would have less output similar to this below.

Pipe: to Less

Your wallpaper might be different than mine.

Similar Code: [ BASH native ] [ Perl uni IO ] [ Perl uni open ] [ Python subProcess] [ Ruby popen ] [ PHP popen ] [ Lua popen ] [ Haskell createProcess ]


How does it works ?

PHP act as middle man, anything read from $pipein written to $pipeout

while(!feof($pipein)) {
    $buffer = fgets($pipein);
    fwrite($pipeout, $buffer);
    flush();
}

A Unidirectional Pipe from Internal Function

Still with popen. Instead of using pipein , we use internal function as source feed. And pipeout to external command.

Do not forget to flush.

Source:

#!/usr/bin/php56  
<?php 

$timeformat = '%a %b %d %H:%M:%S';

$cmdout  = 'less'; # or 'dzen2'
$pipeout = popen($cmdout, "w");

do {
    $datestr = strftime($timeformat)."\n";
    fwrite($pipeout, $datestr);
    flush();
    sleep(1);
} while (true);

pclose($pipeout);

Similar Code: [ BASH pipe ] [ Perl pipe open ] [ Perl pipe IO ] [ Python subProcess ] [ Ruby pipe IO ] [ Ruby popen ] [ Ruby open3 ] [ Ruby PTY ] [ PHP popen ] [ Lua popen ] [ Haskell createProcess ]


How does it works ?

The same as previous. But instead of reading from $pipein, it is managed by internal process using fwrite($pipeout, ...).

    $datestr = strftime($timeformat)."\n";
    fwrite($pipeout, $datestr)

Fork Overview

This step use internal function as source feed, as continuation of previous step.

This step use dzen2, with complete parameters. This dzen2 is forked, running in the background. Detached from the script, no need to wait for dzen2 to finish the script.

Source:

#!/usr/bin/php56  
<?php 

function get_dzen2_parameters() 
{ 
    $xpos    = 0;
    $ypos    = 0;
    $width   = 640;
    $height  = 24;
    $fgcolor = "#000000";
    $bgcolor = "#ffffff";
    $font    = "-*-fixed-medium-*-*-*-12-*-*-*-*-*-*-*";

    $parameters  = "  -x $xpos -y $ypos -w $width -h $height";
    $parameters .= " -fn '$font'";
    $parameters .= " -ta c -bg '$bgcolor' -fg '$fgcolor'";
    $parameters .= " -title-name dzentop";

    return $parameters;
}

function generated_output($process)
{
    $timeformat = '%a %b %d %H:%M:%S';

    do {
        $datestr = strftime($timeformat)."\n";
        fwrite($process, $datestr);
        flush();
        sleep(1);
    } while (true);
}

function run_dzen2() 
{ 
    $cmdout  = 'dzen2 '.get_dzen2_parameters();
    $pipeout = popen($cmdout, "w");

    generated_output($pipeout);

    pclose($pipeout);
}

function detach_dzen2() 
{ 
    $pid = pcntl_fork();
    
    switch($pid) {         
         case -1 : die('could not fork'); // fork errror         
         case 0  : run_dzen2(); break;    // we are the child
         default : return $pid;           // we are the parent             
    }    
}

# ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----
# main

# remove all dzen2 instance
system('pkill dzen2');

# run process in the background
detach_dzen2();

This step also add system command that kill any previous dzen2 instance. So it will be guaranteed, that the dzen2 shown is coming from the latest script.

Similar Code: [ BASH fork ] [ Perl fork ] [ Python fork ] [ Ruby fork ] [ PHP fork ] [ Lua fork ] [ Haskell fork ]


How does it works ?

Any code after the pcntl_fork() executed in both parent and child. The child process has been detached from parent process. The only different is the $pid.

function detach_dzen2() 
{ 
    $pid = pcntl_fork();
    
    switch($pid) {         
         case -1 : die('could not fork'); // fork errror         
         case 0  : run_dzen2(); break;    // we are the child
         default : return $pid;           // we are the parent             
    }    
}

Polishing The Script

This step, we use conky again, as a source feed. And also parameterized dzen2 as continuation of previous step.

This step add optional transset transparency, detached from script. So we two forks, dzen and transset.

Source:

#!/usr/bin/php56  
<?php 

function get_dzen2_parameters() 
{ 
    $xpos    = 0;
    $ypos    = 0;
    $width   = 640;
    $height  = 24;
    $fgcolor = "#000000";
    $bgcolor = "#ffffff";
    $font    = "-*-fixed-medium-*-*-*-12-*-*-*-*-*-*-*";

    $parameters  = "  -x $xpos -y $ypos -w $width -h $height";
    $parameters .= " -fn '$font'";
    $parameters .= " -ta c -bg '$bgcolor' -fg '$fgcolor'";
    $parameters .= " -title-name dzentop";

    return $parameters;
}

function generated_output($process)
{
    $path    = __dir__."/../assets";
    $cmdin   = 'conky -c '.$path.'/conky.lua';
    $pipein  = popen($cmdin,  "r"); # handle
    
    while(!feof($pipein)) {
        $buffer = fgets($pipein);
        fwrite($process, $buffer);
        flush();
    }
    
    pclose($pipein);
}

function run_dzen2() 
{ 
    $cmdout  = 'dzen2 '.get_dzen2_parameters();
    $pipeout = popen($cmdout, "w");

    generated_output($pipeout);

    pclose($pipeout);
}

function detach_dzen2() 
{ 
    $pid = pcntl_fork();
    
    switch($pid) {         
         case -1 : die('could not fork'); // fork errror         
         case 0  : run_dzen2(); break;    // we are the child
         default : return $pid;           // we are the parent             
    }    
}

function detach_transset() { 
    $pid = pcntl_fork();
    if ($pid == 0) { 
        sleep(1);
        system('transset .8 -n dzentop >/dev/null 2');
    }
}

# ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----
# main

# remove all dzen2 instance
system('pkill dzen2');

# run process in the background
detach_dzen2();

# optional transparency
detach_transset();

This would have dzen2 output similar to this below.

Pipe: to Dzen2


How does it works ?

Nothing new here.

There above are some simple codes I put together. I’m mostly posting codes so I won’t have any problems finding it in the future.

Thank you for reading.