Hướng dẫn php unique process id

I want to run a php script on background and store its PID on database. So that I can check if the particular script running or not (later).

We can use getmypid to get current PID.

But as per the PHP manual

Process IDs are not unique, thus they are a weak entropy source. We recommend against relying on pids in security-dependent contexts.

...and I cannot rely on PID.

My second idea is to store the process created time to the database.

How can I get the current script created time? And later how can I compare with tasklist to check whether the particular script is running or not?

I am running on a shared host, windows/linux environment.

BenMorel

32.6k48 gold badges170 silver badges302 bronze badges

asked Jul 26, 2013 at 6:17

4

From php.net/getmypid

with little modification to disable non cli access.

script can be executed using /usr/bin/php script.php.

Additionally use nohup /usr/bin/php script.php > nohup.out & to launch a nohup process in background.

#!/usr/bin/php 

answered Jul 26, 2013 at 6:45

Hướng dẫn php unique process id

PrasanthPrasanth

5,1492 gold badges28 silver badges61 bronze badges

It all depends on your level of access to target machine. You can use PHP CLI, store PIDs (they are unique to particular point in time, so you won't have 2 processes with same PIDs running) and grep them in the output of ps -ax to check if they are running. If not - delete them from database, so that you won't have problem with the same PID occuring.

answered Jul 26, 2013 at 6:32

David JashiDavid Jashi

4,4681 gold badge20 silver badges26 bronze badges

1

You can try use the PID with another id, for example:

if you have a zipping job that uses a file id = 327, try to store {PID}327, and with this check if this particular job still running.

Even if the PID get reused, you will not have that PID with id 327 stored, or if you restart the zipping process with this particular id 327, probabily the PID will change.

But, to avoid get the same PID with this id 327, you'll have to check your database before, and then add a counter at the end of the composed id, like {PID}327_1.

Hope this can help you.

answered Aug 2, 2018 at 16:38

Not the answer you're looking for? Browse other questions tagged php or ask your own question.

(PHP 4, PHP 5, PHP 7, PHP 8)

getmypidGets PHP's process ID

Description

getmypid(): int|false

Parameters

This function has no parameters.

Return Values

Returns the current PHP process ID, or false on error.

Notes

Warning

Process IDs are not unique, thus they are a weak entropy source. We recommend against relying on pids in security-dependent contexts.

See Also

  • getmygid() - Get PHP script owner's GID
  • getmyuid() - Gets PHP script owner's UID
  • get_current_user() - Gets the name of the owner of the current PHP script
  • getmyinode() - Gets the inode of the current script
  • getlastmod() - Gets time of last page modification

Radu Cristescu

9 years ago

The lock-file mechanism in Kevin Trass's note is incorrect because it is subject to race conditions.

For locks you need an atomic way of verifying if a lock file exists and creating it if it doesn't exist. Between file_exists and file_put_contents, another process could be faster than us to write the lock.

The only filesystem operation that matches the above requirements that I know of is symlink().

Thus, if you need a lock-file mechanism, here's the code. This won't work on a system without /proc (so there go Windows, BSD, OS X, and possibly others), but it can be adapted to work around that deficiency (say, by linking to your pid file like in my script, then operating through the symlink like in Kevin's solution).

#!/usr/bin/php

define

('LOCK_FILE', "/var/run/" . basename($argv[0], ".php") . ".lock");

if (!

tryLock())
    die(
"Already running.\n");# remove the lock on exit (Control+C doesn't count as 'exit'?)
register_shutdown_function('unlink', LOCK_FILE);# The rest of your script goes here....
echo "Hello world!\n";
sleep(30);

exit(

0);

function

tryLock()
{
   
# If lock file exists, check if stale.  If exists and is not stale, return TRUE
    # Else, create lock file and return FALSE.
if (@symlink("/proc/" . getmypid(), LOCK_FILE) !== FALSE) # the @ in front of 'symlink' is to suppress the NOTICE you get if the LOCK_FILE exists
       
return true;# link already exists
    # check if it's stale
   
if (is_link(LOCK_FILE) && !is_dir(LOCK_FILE))
    {
       
unlink(LOCK_FILE);
       
# try to lock again
       
return tryLock();
    }

    return

false;
}
?>

Robert Mays Jr

11 years ago

All of the examples above require you to have shell command execution turned on- this example uses only PHP functions and should work on any system (posix is included by default)-

the key is posix_getsid which will return FALSE if the processes does not exist.

$lockfile = sys_get_temp_dir() . '/myScript.lock';
$pid = file_get_contents($lockfile);
if (
posix_getsid($pid) === false) {
   print
"process has died! restarting...\n";
  
file_put_contents($lockfile, getmypid()); // create lockfile
} else {
   print
"PID is still alive! can not run twice!\n";
   exit;
}
?>

:-) perfect if you need to make sure a cron job or shell script has ended before it can be started again.

This works across users- if the cron job is started as 'root' your 'web user' can see if the process is still alive (useful for system status pages)

brooke at jump dot net

18 years ago

One good use for this is deciding on a concurrency-safe temporary file or directory name. You can be assured that no two processes on the same server have the same PID, so this is enough to avoid collisions. For example:

$tmpfile = "/tmp/foo_".getmypid();
// Use $tmpfile...
// Use $tmpfile...
// Use $tmpfile...
unlink ($tmpfile);
?>

If you are sharing /tmp over the network (which is odd....) then you can, of course, mix in the PHP server's IP address.

Kevin Traas (ktraas- at -gmail dot com)

12 years ago

Looking to create a lock-file mechanism for a cmd-line script?

Enjoy!

#!/usr/bin/php

define

( 'LOCK_FILE', "/var/run/".basename( $argv[0], ".php" ).".lock" );
if(
isLocked() ) die( "Already running.\n" ); # The rest of your script goes here....
echo "Hello world!\n";
sleep(30); unlink( LOCK_FILE );
exit(
0);

function

isLocked()
{
   
# If lock file exists, check if stale.  If exists and is not stale, return TRUE
    # Else, create lock file and return FALSE.
if( file_exists( LOCK_FILE ) )
    {
       
# check if it's stale
       
$lockingPID = trim( file_get_contents( LOCK_FILE ) ); # Get all active PIDs.
       
$pids = explode( "\n", trim( `ps -e | awk '{print $1}'` ) ); # If PID is still active, return true
       
if( in_array( $lockingPID, $pids ) )  return true; # Lock-file is stale, so kill it.  Then move on to re-creating it.
       
echo "Removing stale lock file.\n";
       
unlink( LOCK_FILE );
    }
file_put_contents( LOCK_FILE, getmypid() . "\n" );
    return
false;

}

?>

martijn at nowhere dot com

6 years ago

On windows, you can get a list of PID's using this single line statement: = array_column(array_map('str_getcsv', explode("\n",trim(`tasklist /FO csv /NH`))), 1); ?>.

brospam at gmail dot com

9 years ago

My lockfile system

function isLocked(){
    if(
file_exists(LOCK_FILE)) {
       
$lockingPID = trim(file_get_contents(LOCK_FILE));
       
$test=trim(`ps -p $lockingPID -o pid=`);
        if(!empty(
$test)) return true;
        echo
"Removing stale lock file.\n";
       
unlink(LOCK_FILE);
    }
   
file_put_contents(LOCK_FILE, getmypid()."\n");
    return
false;
}
?>

Erickson Reyes ercbluemonday at yahoo dot com

12 years ago

We also had this challenge in our company to prevent a php script in a cron job from overlapping each other.

We made this solution

        // Initialize variables
   
$found            = 0;
   
$file                 = basename(__FILE__);
   
$commands    = array();// Get running processes.
   
exec("ps w", $commands);// If processes are found
   
if (count($commands) > 0) {

        foreach (

$commands as $command) {
            if (
strpos($command, $file) === false) {
                              
// Do nothin'
           
}
            else {
                              
// Let's count how many times the file is found.
               
$found++;
            }
        }
    }
// If the instance of the file is found more than once.
   
if ($found > 1) {
        echo
"Another process is running.\n";
        die();
    }
/**
        *
        * Regular process here...
        *
        */
?>

eight_hf at live dot fr

10 years ago

On Linux you can check if a process is still running by verifying if the PID exists in the /proc directory :

if(file_exists('/proc/'.$pid))
{
    echo
'The process is still running.';
}
?>

kroczu at interia dot pl

16 years ago

/*

mixed getpidinfo(mixed pid [, string system_ps_command_options])

this function gets PID-info from system ps command and return it in useful assoc-array,
or return false and trigger warning if PID doesn't exists

$pidifo=getpidinfo(12345);

print_r($pidifo);

Array
(
    [USER] => user
    [PID] => 12345
    [%CPU] => 0.0
    [%MEM] => 0.0
    [VSZ] => 1720
    [RSS] => 8
    [TT] => ??
    [STAT] => Is
    [STARTED] => 6:00PM
    [TIME] => 0:00.01
    [COMMAND] => php someproces.php > logfile
)

*/

//////////////////////////////////////////////

function getpidinfo($pid, $ps_opt="aux"){ $ps=shell_exec("ps ".$ps_opt."p ".$pid);
  
$ps=explode("\n", $ps);

      if(

count($ps)<2){
     
trigger_error("PID ".$pid." doesn't exists", E_USER_WARNING);
      return
false;
   }

   foreach(

$ps as $key=>$val){
     
$ps[$key]=explode(" ", ereg_replace(" +", " ", trim($ps[$key])));
   }

   foreach(

$ps[0] as $key=>$val){
     
$pidinfo[$val] = $ps[1][$key];
      unset(
$ps[1][$key]);
   }

      if(

is_array($ps[1])){
     
$pidinfo[$val].=" ".implode(" ", $ps[1]);
   }
   return
$pidinfo;
}
?>

Pure-PHP

17 years ago

You can use this function also to avoid more than one instance of your app.

You can also use this class.
http://www.pure-php.de/node/20

Usage:

inlude

("ProcessHandler.class.php");

if(

ProcessHandler::isActive()){
   die(
"Already running!\n";);
}else{
  
ProcessHandler::activate();
  
//run my app
}?>

wouter99999 at gmail dot com

11 years ago

On windows, ps is not available. Instead, to view a list of running processes, you can use exec('tasklist'); To kill processes you can use exec('taskkill); Enter taskkill /? for more information.

james at voodoo dot co dot uk

12 years ago

The 'ps' command has an option that can make filtering for a specific process more efficient.  Using this the work of looking for matching processes can be made neater:

    /*
    Return an array of the pids of the processes that are running for the specific command
    e.g.
        returnPids('myprocess.php');
    */
   
function returnPids($command) {
       
exec("ps -C $command -o pid=",$pids);
        foreach (
$pids as $key=>$value) $pids[$key]=trim($value);
        return
$pids;
    }   
/*
    Returns an array of the pids for processes that are like me, i.e. my program running
    */
   
function returnMyPids() {
        return
returnPids(basename($_SERVER["SCRIPT_NAME"]));
    }
?>

e.g. to bomb out if I'm running already

if (count(returnMyPids())>1) exit;

pdc at example dot com

10 years ago

Here is how you'd use exec on a posix system to accomplish counting processes quickly.

I want to know how many processes are running with 'update.php' in the command:

ps aux|grep "[u]pdate.php"|wc -l

(the trick of using [u]pdate.php instead of update.php makes sure that the grep command itself is not matched).  Be sure to use quotes in the command, or it won't work either.

So, the code:

function countProcesses($scriptName)
{
   
// ps aux|grep "[u]pdate.php"|wc -l
   
$first    =    substr($scriptName, 0, 1);
   
$rest    =    substr($scriptName, 1); $name    =    '"['.$first.']'.$rest.'"';
   
$cmd    =    "ps aux | grep $name | wc -l"; $result    =    exec($cmd);

                return

$result;
}
?>

gabe at fijiwebdesign dot com

12 years ago

Based on what james at voodoo dot co dot uk said, but modified for CLI scripts (ie: there is no $_SERVER).

/**
* Check for a current process by filename
* @param $file[optional] Filename
* @return Boolean
*/
function processExists($file = false) {$exists     = false;
   
$file       = $file ? $file : __FILE__;// Check if file is in process list
   
exec("ps -C $file -o pid=", $pids);
    if (
count($pids) > 1) {
       
$exists = true;
    }
    return
$exists;
}
?>