PHP Conference Japan 2024

shmop_open

(PHP 4 >= 4.0.4, PHP 5, PHP 7, PHP 8)

shmop_open建立或開啟共享記憶體區塊

描述

shmop_open(
    int $key,
    string $mode,
    int $permissions,
    int $size
):Shmop|false

shmop_open() 可以建立或開啟共享記憶體區塊。

參數

key

系統的共享記憶體區塊 ID。可以傳遞十進制或十六進制。

mode

您可以使用的旗標

  • 「a」表示存取(為 shmat 設定 SHM_RDONLY),當您需要開啟現有的共享記憶體區段以進行唯讀時,請使用此旗標
  • 「c」表示建立(設定 IPC_CREATE),當您需要建立新的共享記憶體區段,或者如果存在具有相同金鑰的區段,請嘗試開啟以進行讀寫時,請使用此旗標
  • 「w」表示讀取和寫入存取,當您需要讀取和寫入共享記憶體區段時,請使用此旗標,在大多數情況下使用此旗標。
  • 「n」建立新的記憶體區段(設定 IPC_CREATE|IPC_EXCL),當您想要建立新的共享記憶體區段,但如果已經存在具有相同旗標的區段,則會失敗。這對於安全性很有用,使用此功能可以防止競爭條件漏洞。

permissions

您希望指派給記憶體區段的權限,這些權限與檔案的權限相同。權限需要以八進制形式傳遞,例如 0644

size

您希望建立的共享記憶體區塊大小(以位元組為單位)

注意:

注意:如果您要開啟現有的記憶體區段,則第 3 和第 4 個參數應輸入為 0。

傳回值

成功時,shmop_open() 將傳回一個 Shmop 實例,您可以使用該實例來存取您已建立的共享記憶體區段。失敗時會傳回 false

錯誤/例外

如果 mode 無效,或 size 小於或等於零,則會拋出 ValueError。在其他失敗情況下,會發出 E_WARNING

變更記錄

版本 描述
8.0.0 成功時,此函數現在會傳回一個 Shmop 實例;先前會傳回一個 resource
8.0.0 如果 mode 無效,或 size 小於或等於零,則會拋出 ValueError;先前會發出 E_WARNING,並且函數會傳回 false

範例

範例 1 建立新的共享記憶體區塊

<?php
$shm_key
= ftok(__FILE__, 't');
$shm_id = shmop_open($shm_key, "c", 0644, 100);
?>

此範例開啟了一個共享記憶體區塊,其系統 ID 由 ftok() 傳回。

參見

新增註解

使用者貢獻的註解 9 個註解

kakkau at grr dot la
8 年前
在 *nix 系統上,當設定 $key = 0 時,shmop_open 能夠建立「無限」數量的區段。

在互動式 Shell 中執行下列命令兩次後
php > $res = shmop_open(0,"n",0600,1024);

列出目前存在的記憶體區段
$ ipcs -m

------ 共享記憶體區段 --------
key shmid owner perms bytes nattch status
0x00000000 2293762 user 600 1024 0
0x00000000 2326531 user 600 1024 0

對於任何整數 <> 0 與旗標「n」結合使用,shmop_open 的運作方式與文件記載的一樣。它會失敗。
daniele_dll at yahoo dot it
20 年前
有一個小的 ftok 函數。此函數未包含在 Windows 的 PHP 中,所以我直接從 Linux glibc 2.3.2 原始碼中取得了它。我希望這會有用。
這是程式碼

<?php
function ftok($pathname, $proj_id) {
$st = @stat($pathname);
if (!
$st) {
return -
1;
}

$key = sprintf("%u", (($st['ino'] & 0xffff) | (($st['dev'] & 0xff) << 16) | (($proj_id & 0xff) << 24)));
return
$key;
}

echo
ftok($_SERVER["SCRIPT_FILENAME"], 250);
?>

抱歉我的英文不好 :)
Craig Manley
19 年前
致:macmaster at pobox dot com

澄清一些新的混淆:您說 shm 金鑰的長度是 8 個位元組。據我所知,它是 4 個位元組(32 位元)。
請查看下面 Linux 上 ipcs 的輸出,以了解我的意思。

------ 共享記憶體區段 --------
key shmid owner perms bytes nattch status
0x6e6a694d 65538 mijnbel 644 65536 0
0x326e794d 98307 mijnbel 644 65536 0
0x62417347 131076 smsklap 644 65536 0
erelsgl at gmail dot com
17 年前
=== 檢查共享記憶體是否存在 ===
Mitchell_Shnier at ieee dot orgZ 提供的解決方案在我的電腦上不起作用 - 我收到一個警告「旗標 ac 無效」。

為了檢查共享記憶體是否存在,您只需使用「a」或「w」旗標開啟它,同時使用「@」運算子隱藏警告即可
<?php
@$shid = shmop_open($systemId, "a", 0666, 0);
if (!empty(
$shid)) {
...
共享記憶體存在
} else {
...
共享記憶體不存在
}
?>
Filippo Fadda
9 年前
我在 Mac OS X Lion 上遇到了與下方描述的 XP 相同的問題。

要解決這個問題,請先使用 'a' 旗標,然後使用 'n' 旗標。避免使用 'c' 旗標。

<?php
$str
= 'Hello World';

shm_key = ftok($_SERVER['PHP_SELF']);

if (@
$shm_id = shmop_open($shm_key, 'a', 0644, 0))
shmop_delete($shm_id);

$shm_id = shmop_open($shm_key, 'n', 0644, strlen($str));

if (
$shmId) {
shmop_write($shmId, $str, 0);
shmop_close($shmId);
}
else
throw new
RuntimeException("無法建立共享記憶體區段。");
?>
kakkau at grr dot la
6 年前
無法重新連線到金鑰為 0 的區段。對於任何其他金鑰(例如 1),這些旗標都可以正常運作。

php > $soid = shmop_open(0,"n",0600,10);
php > $soid = shmop_open(0,"w",0600,10);
PHP 警告:shmop_open():無法附加或建立共享記憶體區段 '無效的參數' 在第 1 行 php shell code 中
PHP 堆疊追蹤
PHP 1. {main}() php shell code:0
PHP 2. shmop_open(0, 'w', 384, 10) php shell code:1
thanks at forthefish dot com
11 年前
這些共享記憶體函式在 Windows 上有點笨拙,因為在 Windows 上 sem_get() 和相關函式,以及任何類型的同步物件都無法使用(截至 PHP 5.5.5),因此無法在存取之前執行適當的鎖定。PHP 核心開發人員需要為 Windows 撰寫一些 sem_get() 的封裝函式,就像他們為 shmop 所做的那樣,才能真正完善這個功能。

Windows 的 shmop 實作相當巧妙 - 作者基本上將 POSIX 函式的變體移植到 Windows 對應的原型。
Chris Petersen
21 年前
請注意,如果您嘗試使用設定為零的金鑰來 shmop_open,shmop_open 看似會正常運作,而且您可以寫入,但您將無法從中讀取或刪除它。如果您不小心,您可以繼續這樣做 - 在「零」處建立越來越多的共享記憶體區塊,直到最後您將開始收到錯誤訊息,指出 php 無法存取或建立共享記憶體區塊,而且您將必須重新啟動電腦才能釋放所有這些「零」區塊。
Colin Paterson
9 年前
如果您以例如「root」使用者身分執行主要腳本,但需要以其他使用者(從您的主要腳本)例如「www-data」身分開啟共享記憶體區段,則此方法可行

exec("sudo -u www-data php -r 'shmop_open(0xee4, "c", 0770, 100);'"); //以使用者 www-data 身分建立共享記憶體區段

$SharedMemorySegment = shmop_open(0xee4, "c", 0770, 100);
if (!$SharedMemorySegment) {
echo "無法建立共享記憶體區段\n";
}
To Top