PHP Conference Japan 2024

getmypid

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

getmypid获取 PHP 的进程 ID

说明

getmypid(): int|false

获取当前 PHP 进程的 ID。

参数

此函数没有参数。

返回值

返回当前 PHP 进程的 ID,错误时返回 false

注释

警告

进程 ID 不是唯一的,因此它们是一个弱熵源。我们建议不要在依赖安全性的上下文中使用进程 ID。

参见

添加注释

用户贡献的注释 14 条

up
41
Radu Cristescu
11 年前
Kevin Trass 笔记中的锁文件机制是不正确的,因为它容易受到竞态条件的影响。

对于锁,您需要一种原子方式来验证锁文件是否存在,并在不存在时创建它。在 file_exists 和 file_put_contents 之间,另一个进程可能比我们更快地写入锁。

我知道的唯一符合上述要求的文件系统操作是 symlink()。

因此,如果您需要锁文件机制,以下是代码。这在没有 /proc 的系统上不起作用(因此 Windows、BSD、OS X 和其他系统可能不行),但可以进行调整以解决该缺陷(例如,像我的脚本中那样链接到您的 pid 文件,然后像 Kevin 的解决方案中那样通过符号链接操作)。

#!/usr/bin/php
<?php

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

if (!
tryLock())
die(
"已经在运行。\n");

# 退出时删除锁(Control+C 不算作“退出”?)
register_shutdown_function('unlink', LOCK_FILE);

# 您的脚本的其余部分放在这里....
echo "Hello world!\n";
sleep(30);

exit(
0);

function
tryLock()
{
# 如果锁文件存在,检查是否过期。如果存在且未过期,则返回 TRUE
# 否则,创建锁文件并返回 FALSE。

if (@symlink("/proc/" . getmypid(), LOCK_FILE) !== FALSE) # 'symlink' 前面的 @ 用于抑制 LOCK_FILE 存在时出现的通知
return true;

# 链接已存在
# 检查是否过期
if (is_link(LOCK_FILE) && !is_dir(LOCK_FILE))
{
unlink(LOCK_FILE);
# 再次尝试锁定
return tryLock();
}

return
false;
}
?>
up
3
Robert Mays Jr
13 年前
以上所有示例都要求您启用 shell 命令执行 - 此示例仅使用 PHP 函数,应该可以在任何系统上运行(posix 默认包含在内)-

关键是 posix_getsid,如果进程不存在,它将返回 FALSE。

<?php
$lockfile
= sys_get_temp_dir() . '/myScript.lock';
$pid = file_get_contents($lockfile);
if (
posix_getsid($pid) === false) {
print
"进程已死!正在重新启动...\n";
file_put_contents($lockfile, getmypid()); // 创建锁文件
} else {
print
"PID 仍然存在!不能运行两次!\n";
exit;
}
?>

:-) 如果您需要确保 cron 作业或 shell 脚本已结束才能再次启动,那么这是完美的。

这可以跨用户工作 - 如果 cron 作业以 'root' 身份启动,您的 'web 用户' 可以查看该进程是否仍然存在(对于系统状态页面很有用)
up
1
brospam at gmail dot com
11 年前
我的锁文件系统

<?php
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
"正在删除过期的锁文件。\n";
unlink(LOCK_FILE);
}
file_put_contents(LOCK_FILE, getmypid()."\n");
return
false;
}
?>
up
2
Kevin Traas (ktraas- at -gmail dot com)
15 年前
想要为命令行脚本创建一个锁文件机制吗?

请尽情使用!

#!/usr/bin/php
<?php

define
( 'LOCK_FILE', "/var/run/".basename( $argv[0], ".php" ).".lock" );
if(
isLocked() ) die( "已在运行中。\n" );

# 你的脚本的其余部分写在这里....
echo "Hello world!\n";
sleep(30);

unlink( LOCK_FILE );
exit(
0);

function
isLocked()
{
# 如果锁文件存在,检查它是否过时。如果存在且未过时,返回 TRUE
# 否则,创建锁文件并返回 FALSE。

if( file_exists( LOCK_FILE ) )
{
# 检查它是否过时
$lockingPID = trim( file_get_contents( LOCK_FILE ) );

# 获取所有活动的 PID。
$pids = explode( "\n", trim( `ps -e | awk '{print $1}'` ) );

# 如果 PID 仍然有效,返回 true
if( in_array( $lockingPID, $pids ) ) return true;

# 锁文件已过时,将其删除。然后继续重新创建它。
echo "正在删除过时的锁文件。\n";
unlink( LOCK_FILE );
}

file_put_contents( LOCK_FILE, getmypid() . "\n" );
return
false;

}
?>
up
1
brooke at jump dot net
21 年前
这种方法的一个很好的用途是确定一个并发安全的临时文件或目录名称。你可以确信同一服务器上没有两个进程具有相同的 PID,因此这足以避免冲突。例如:

<?php
$tmpfile
= "/tmp/foo_".getmypid();
// 使用 $tmpfile...
// 使用 $tmpfile...
// 使用 $tmpfile...
unlink ($tmpfile);
?>

如果你正在通过网络共享 /tmp(这很奇怪....),那么你当然可以混合使用 PHP 服务器的 IP 地址。
up
0
wouter99999 at gmail dot com
13 年前
在 Windows 上,ps 不可用。相反,要查看正在运行的进程列表,你可以使用 exec('tasklist'); 要终止进程,你可以使用 exec('taskkill'); 输入 taskkill /? 以获取更多信息。
up
-1
eight_hf at live dot fr
12 年前
在 Linux 上,你可以通过验证 /proc 目录中是否存在 PID 来检查进程是否仍在运行

<?php
if(file_exists('/proc/'.$pid))
{
echo
'该进程仍在运行。';
}
?>
up
-1
kroczu at interia dot pl
18 年前
<?php
/*

mixed getpidinfo(mixed pid [, string system_ps_command_options])

此函数从系统 ps 命令获取 PID 信息并以有用的关联数组形式返回它,
如果 PID 不存在,则返回 false 并触发警告

$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." 不存在", 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;
}

?>
up
-1
Erickson Reyes ercbluemonday at yahoo dot com
15 年前
我们公司也遇到了这个挑战,需要防止 cron 作业中的 php 脚本相互重叠。

我们制定了这个解决方案

<?php
// 初始化变量
$found = 0;
$file = basename(__FILE__);
$commands = array();

// 获取正在运行的进程。
exec("ps w", $commands);

// 如果找到进程
if (count($commands) > 0) {

foreach (
$commands as $command) {
if (
strpos($command, $file) === false) {
// 什么也不做
}
else {
// 让我们计算找到该文件的次数。
$found++;
}
}
}

// 如果该文件的实例被发现不止一次。
if ($found > 1) {
echo
"另一个进程正在运行。\n";
die();
}

/**
*
* 此处为常规进程...
*
*/
?>
up
-1
pdc at example dot com
12 年前
以下是如何在 posix 系统上使用 exec 快速完成进程计数的方法。

我想知道有多少个进程的命令中包含 'update.php'

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

(使用 [u]pdate.php 而不是 update.php 的技巧可确保 grep 命令本身不被匹配)。请务必在命令中使用引号,否则它也将不起作用。

所以,代码:

<?php
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;
}
?>
up
-2
martijn 在 nowhere 点 com
8 年前
在 Windows 上,您可以使用以下单行语句获取 PID 列表:<?php $pids = array_column(array_map('str_getcsv', explode("\n",trim(`tasklist /FO csv /NH`))), 1); ?>
up
-2
Pure-PHP
19 年前
您也可以使用此函数来避免应用程序的多个实例。

您还可以使用此类。
http://www.pure-php.de/node/20

用法

<?php

inlude
("ProcessHandler.class.php");

if(
ProcessHandler::isActive()){
die(
"已经在运行!\n";);
}else{
ProcessHandler::activate();
//运行我的应用程序
}

?>
up
-2
gabe 在 fijiwebdesign 点 com
14 年前
基于 james 在 voodoo 点 co 点 uk 所说的内容,但针对 CLI 脚本进行了修改(即:没有 $_SERVER)。

<?php

/**
* 通过文件名检查当前进程
* @param $file[可选] 文件名
* @return Boolean
*/
function processExists($file = false) {

$exists = false;
$file = $file ? $file : __FILE__;

// 检查文件是否在进程列表中
exec("ps -C $file -o pid=", $pids);
if (
count($pids) > 1) {
$exists = true;
}
return
$exists;
}

?>
up
-3
james 在 voodoo 点 co 点 uk
14 年前
“ps”命令有一个选项可以使过滤特定进程更有效。使用此选项可以使查找匹配进程的工作更简洁。

<?php
/*
返回特定命令正在运行的进程的 pid 数组
例如
returnPids('myprocess.php');
*/
function returnPids($command) {
exec("ps -C $command -o pid=",$pids);
foreach (
$pids as $key=>$value) $pids[$key]=trim($value);
return
$pids;
}

/*
返回与我相似的进程的 pid 数组,即我的程序正在运行
*/
function returnMyPids() {
return
returnPids(basename($_SERVER["SCRIPT_NAME"]));
}
?>

例如,如果我已经运行,则退出

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