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 則註解

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 "你好,世界!\n";
sleep(30);

exit(
0);

function
tryLock()
{
# 如果鎖定檔案存在,請檢查是否過時。如果存在且不過時,則回傳 TRUE
# 否則,建立鎖定檔案並回傳 FALSE。

if (@symlink("/proc/" . getmypid(), LOCK_FILE) !== FALSE) # 'symlink' 前面的 @ 是為了抑制如果 LOCK_FILE 存在時您會收到的 NOTICE
return true;

# 連結已存在
# 檢查是否過時
if (is_link(LOCK_FILE) && !is_dir(LOCK_FILE))
{
unlink(LOCK_FILE);
# 再次嘗試鎖定
return tryLock();
}

return
false;
}
?>
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」身分啟動,您的「網頁使用者」可以看到程序是否仍在執行(對系統狀態頁面很有用)
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;
}
?>
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( "Already running.\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;

}
?>
1
brooke at jump dot net
21 年前
此方法的一個好用處是決定一個並行安全 (concurrency-safe) 的暫存檔案或目錄名稱。您可以確保同一伺服器上的任何兩個進程都沒有相同的 PID,因此這足以避免衝突。例如:

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

如果您透過網路共享 /tmp(這很奇怪...),那麼您當然可以混入 PHP 伺服器的 IP 位址。
0
wouter99999 at gmail dot com
13 年前
在 Windows 上,ps 不可用。相反,要檢視執行中的處理程序清單,您可以使用 exec('tasklist'); 要終止處理程序,您可以使用 exec('taskkill'); 輸入 taskkill /? 以獲取更多資訊。
-1
eight_hf at live dot fr
12 年前
在 Linux 上,您可以透過驗證 /proc 目錄中是否存在 PID 來檢查處理程序是否仍在執行

<?php
if(file_exists('/proc/'.$pid))
{
echo
'處理程序仍在執行。';
}
?>
-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;
}

?>
-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();
}

/**
*
* 這裡是一般的處理程序...
*
*/
?>
-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;
}
?>
-2
martijn at nowhere dot com
8 年前
在 Windows 上,您可以使用這單行陳述式來取得 PID 清單:<?php $pids = array_column(array_map('str_getcsv', explode("\n",trim(`tasklist /FO csv /NH`))), 1); ?>
-2
Pure-PHP
19 年前
您也可以使用此函數來避免應用程式有多個執行個體。

您也可以使用這個類別。
http://www.pure-php.de/node/20

使用方法

<?php

inlude
("ProcessHandler.class.php");

if(
ProcessHandler::isActive()){
die(
"Already running!\n";);
}else{
ProcessHandler::activate();
//執行我的應用程式
}

?>
-2
gabe at fijiwebdesign dot com
14 年前
根據 james at voodoo dot co dot uk 所說的,但針對 CLI 腳本進行修改(即:沒有 $_SERVER)。

<?php

/**
* 依據檔名檢查目前是否有處理程序
* @param $file[optional] 檔名
* @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;
}

?>
-3
james at voodoo dot co dot 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