Skip to content

microscrap/posix

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 

Repository files navigation

microscrap/posix — POSIX bindings for ScrapyardIO

PHP library that wraps the posi extension with global helpers and enums. Every helper delegates to Posi\System.

This project provides bindings to the UNIX Portable Operating System Interface (POSIX).

Highlights

  • Retrieve file descriptors to replace fopen
  • Read and write to file descriptors beyond streams, replacing fread and fwrite
  • Direct access to fcntl
  • Direct access to ioctl

Requirements

  • PHP 8.3+
  • ext-posi ^0.4.0 — install from php-io-extensions/posi (see that repo for build and enable instructions)

Installation

Confirm ext-posi is loaded before using this library:

php -m | grep posi
composer require microscrap/posix

Composer autoloads src/Helpers/posix-system.php, registering the global helpers when the package is installed.

Usage

POSIX I/O is invoked through global helper functions (for example posix_open, posix_read). Helpers are only defined if the name is not already taken (function_exists guard).

Optional enums live under Microscrap\Bindings\POSIX\Enums (FileControlFlag, FcntlCommand).

<?php

$fd = posix_open('/dev/null', O_RDWR);
posix_close($fd);

posix_open(), fcntl(), and ioctl() take the same flag and command constants as C (O_RDONLY, F_GETFL, and so on). Define them in PHP or load them from your platform headers; values differ by OS.


Global Helper API

posix_open(string $filepath, int $flags = 2, int $mode = 0644): int

Opens a path and returns a file descriptor (non-negative integer), or -1 on failure (same semantics as C open(2)).

  • $filepath — device node, pipe, socket path, or regular file path.
  • $flagsO_* access mode and creation flags (e.g. O_RDWR, O_CREAT | O_TRUNC). Default 2 (O_RDWR on Linux/glibc).
  • $mode — permission bits when O_CREAT is set (default 0644).

Example — open an existing file for reading

<?php

// O_RDONLY is platform-specific; 0 on Linux/glibc.
$fd = posix_open('/etc/hosts', 0);

if ($fd < 0) {
    throw new RuntimeException('open failed');
}

$chunk = posix_read($fd, 256);
posix_close($fd);

Example — create and truncate a file for read/write

<?php

// Linux/glibc: O_RDWR | O_CREAT | O_TRUNC
$flags = 2 | 64 | 512;

$fd = posix_open('/tmp/posix-demo.txt', $flags, 0644);

if ($fd < 0) {
    throw new RuntimeException('open failed');
}

posix_write($fd, "hello\n", 6);
posix_close($fd);

posix_close(int $fd): int

Closes a file descriptor. Returns 0 on success and -1 on failure (same semantics as C close(2)).

Example

<?php

$fd = posix_open('/dev/null', O_RDWR);

$result = posix_close($fd);
// $result === 0 on success

posix_chmod(string $path, int $mode): int

Sets permission bits on a path. Returns 0 on success and -1 on failure (same semantics as C chmod(2)).

  • $path — file or directory path.
  • $mode — permission bits (e.g. 0644). Combine with S_ISUID, S_ISGID, and S_ISVTX where your platform supports them.

Changing modes on paths you do not own, or setting set-user-ID bits, typically requires appropriate privileges.

Example

<?php

$path = '/tmp/posix-chmod-demo.txt';
$fd = posix_open($path, 2 | 64 | 512, 0644);
posix_close($fd);

if (posix_chmod($path, 0600) !== 0) {
    throw new RuntimeException('chmod failed');
}

posix_chown(string $path, int $owner, int $group): int

Sets owner and group for a path. Returns 0 on success and -1 on failure (same semantics as C chown(2)).

  • $owner — numeric user ID (uid_t).
  • $group — numeric group ID (gid_t).

This call usually requires superuser privileges or capability CAP_CHOWN on Linux.

Example

<?php

$path = '/tmp/owned-by-me.txt';
$fd = posix_open($path, 2 | 64 | 512, 0644);
posix_close($fd);

$uid = (int) posix_getuid();
$gid = (int) posix_getgid();

if (posix_chown($path, $uid, $gid) !== 0) {
    throw new RuntimeException('chown failed');
}

posix_fchmod(int $fd, int $mode): int

Like posix_chmod, but applies to an open file descriptor. Returns 0 on success and -1 on failure (same semantics as C fchmod(2)).

Example

<?php

$fd = posix_open('/tmp/posix-fchmod.txt', 2 | 64 | 512, 0644);

if (posix_fchmod($fd, 0600) !== 0) {
    posix_close($fd);
    throw new RuntimeException('fchmod failed');
}

posix_close($fd);

posix_fchown(int $fd, int $owner, int $group): int

Like posix_chown, but applies to the file referred to by an open descriptor. Returns 0 on success and -1 on failure (same semantics as C fchown(2)).

Example

<?php

$fd = posix_open('/tmp/posix-fchown.txt', 2 | 64 | 512, 0644);

$uid = (int) posix_getuid();
$gid = (int) posix_getgid();

if (posix_fchown($fd, $uid, $gid) !== 0) {
    posix_close($fd);
    throw new RuntimeException('fchown failed');
}

posix_close($fd);

posix_write(int $fd, string $data, int $bytes_to_write): int

Writes up to $bytes_to_write bytes from $data to the descriptor. Returns the number of bytes written, or -1 on failure (same semantics as C write(2)).

Example — write a line to a file descriptor

<?php

$fd = posix_open('/tmp/posix-demo.txt', 2 | 64 | 512, 0644);

$payload = "ping\n";
$written = posix_write($fd, $payload, strlen($payload));

// $written === 5 when all bytes were accepted
posix_close($fd);

Example — write to /dev/null

<?php

$fd = posix_open('/dev/null', O_WRONLY);

posix_write($fd, str_repeat('x', 1024), 1024);
posix_close($fd);

posix_read(int $fd, int $bytes_to_read): string|false

Reads up to $bytes_to_read bytes from the descriptor. Returns a binary string of the bytes read (length may be less than requested). Returns false if the underlying read(2) fails.

Example — read the first 512 bytes of a file

<?php

$fd = posix_open('/etc/hosts', 0);

$data = posix_read($fd, 512);

if ($data === false) {
    throw new RuntimeException('read failed');
}

echo $data;
posix_close($fd);

Example — read from a pipe in a loop

<?php

$fd = /* descriptor from pipe, socket, or device */;

while (true) {
    $chunk = posix_read($fd, 4096);

    if ($chunk === false) {
        break;
    }

    if ($chunk === '') {
        break; // EOF
    }

    // process $chunk
}

posix_getuid(): int

Returns the real user ID of the calling process (same semantics as C getuid(2)).

This helper is registered only when posix_getuid() is not already defined (for example by PHP’s built-in posix extension). When the built-in exists, PHP’s version is used instead.

Example

<?php

$uid = posix_getuid();

posix_setuid(int $uid): int

Sets the real user ID of the calling process. Returns 0 on success and -1 on failure (same semantics as C setuid(2)). Changing UID typically requires appropriate privileges.

Registered only when posix_setuid() is not already defined.

Example

<?php

if (posix_setuid(65534) !== 0) {
    // not privileged or operation denied
}

posix_umask(int $mask): int

Sets the file mode creation mask. Returns the previous umask value (same semantics as C umask(2)). Values are numeric (for example octal 022 is the integer 18 on typical platforms).

Example

<?php

$previous = posix_umask(0077);
// restore prior mask
posix_umask($previous);

posix_lseek(int $fd, int $offset, int $whence): int

Repositions the offset of the open descriptor. Returns the new offset measured in bytes from the beginning of the file, or -1 on failure (same semantics as C lseek(2)). Use SEEK_SET, SEEK_CUR, and SEEK_END from your platform.

Example

<?php

$fd = posix_open('/etc/hosts', 0);

$pos = posix_lseek($fd, 0, SEEK_SET);
posix_close($fd);

posix_recv(int $fd, int $len, int $flags = 0): string|false

Receives up to $len bytes from a socket descriptor (same semantics as C recv(2)). Returns a binary string (possibly shorter than $len), or false on failure. Optional $flags are the usual MSG_* constants for your platform (0 to block until data is available).

Example

<?php

// $sock must be a connected socket FD.
// $data = posix_recv($sock, 4096, 0);

posix_readv(int $fd, array $iovecs): array|false

Scatter-read into several buffers in one syscall (readv(2)). Each element of $iovecs is an associative array:

Key Meaning
len Required. Maximum bytes to place in this segment.
base Optional. If present as a string, up to min(strlen($base), len) bytes are copied into the segment before the read (usually you omit this for a fresh read buffer).

On success, returns:

Key Meaning
res Total bytes read (non-negative), or 0 at EOF.
buffers List of binary strings, one per $iovecs entry, each truncated to the portion of the read that landed in that segment.

Returns false if the syscall fails or if $iovecs is invalid.

Example — two segments from a regular file

<?php

$fd = posix_open('/etc/hosts', 0);

$out = posix_readv($fd, [
    ['len' => 4],
    ['len' => 8],
]);

if ($out !== false) {
    // $out['res'] — total bytes read
    // $out['buffers'][0], $out['buffers'][1] — segment contents
}

posix_close($fd);

fcntl(int $fd, int $command, mixed $arg, mixed &$value): int

Invokes fcntl(2) on the descriptor. Returns the syscall status (0 or non-negative on success, -1 on failure). Command-specific output is written to $value by reference (flag integer for getters like F_GETFL, flock array for lock commands, or echo of the argument for setters).

$arg may be an integer, a boolean, or (for F_GETLK / F_SETLK / F_SETLKW) an array with keys: type, whence, start, len, pid.

Example — read open-file status flags (F_GETFL)

<?php

$fd = posix_open('/tmp/posix-demo.txt', 0);

$value = 0;
$res = fcntl($fd, F_GETFL, 0, $value);

// $res — fcntl status
// $value — current O_* flags as integer
$flags = $value;

posix_close($fd);

Example — enable non-blocking I/O (F_SETFL)

<?php

$fd = posix_open('/tmp/posix-demo.txt', 0);

$current = 0;
fcntl($fd, F_GETFL, 0, $current);
$newFlags = $current | O_NONBLOCK;

$ignored = 0;
fcntl($fd, F_SETFL, $newFlags, $ignored);
posix_close($fd);

Example — advisory lock (F_SETLK)

<?php

$fd = posix_open('/tmp/posix-demo.txt', 2);

$value = 0;
$res = fcntl($fd, F_SETLK, [
    'type'   => F_WRLCK,
    'whence' => SEEK_SET,
    'start'  => 0,
    'len'    => 0,
    'pid'    => 0,
], $value);

// $value contains flock fields after the operation
posix_close($fd);

ioctl(int $fd, int $command, mixed $arg, mixed &$value): int

Invokes ioctl(2) on the descriptor. Returns the syscall status. Output is written to $value by reference: integer, string buffer, or argument echo depending on command and $arg.

$arg may be an integer pointer value, a string buffer, or an array:

  • ['value' => int] — read/write a single integer through the ioctl (value updated in $value).
  • ['bytes' => string] or ['data' => string] — binary buffer in/out.

Example — ioctl with no argument (device-specific command)

<?php

$fd = posix_open('/dev/null', O_RDWR);

$value = 0;
$res = ioctl($fd, SOME_IOCTL_CMD, null, $value);

posix_close($fd);

Example — pass an integer argument

<?php

$fd = posix_open('/dev/some-device', O_RDWR);

$value = 0;
$res = ioctl($fd, SOME_IOCTL_CMD, 0, $value);

posix_close($fd);

Example — integer in/out via array

<?php

$fd = posix_open('/dev/some-device', O_RDWR);

$value = 0;
$res = ioctl($fd, SOME_IOCTL_CMD, ['value' => 1], $value);

// $value holds the updated integer after ioctl
$out = $value;

posix_close($fd);

Example — binary buffer in/out

<?php

$fd = posix_open('/dev/some-device', O_RDWR);

$buffer = str_repeat("\0", 32);
$value = 0;

$res = ioctl($fd, SOME_IOCTL_CMD, ['data' => $buffer], $value);

// $value is the buffer returned from the driver
$response = $value;

posix_close($fd);

posix_wait(?int &$status = null): int

Blocks until any child process exits (implemented with waitpid(-1, …, 0), same idea as wait(2)). Returns the child PID on success, or -1 on error (for example ECHILD when there are no children). If you pass $status by reference, it receives the raw wait status integer for use with pcntl_wifexited(), pcntl_wexitstatus(), and related helpers (or your own bit tests). If the call fails, $status is not updated.

Example

<?php

$pid = pcntl_fork();
if ($pid === 0) {
    exit(42);
}

$status = 0;
$got = posix_wait($status);
// decode with pcntl_wexitstatus($status) when pcntl_wifexited($status)

posix_waitpid(int $pid, ?int &$status = null, int $options = 0): int

Wraps waitpid(2). Use $pid = -1 to wait for any child (same as posix_wait()). $options is typically 0 (block) or WNOHANG (do not block). Returns the child PID on success when a child was reaped, 0 when $options includes WNOHANG and no child was ready, or -1 on error. The raw status word is written to $status by reference only when the return value is greater than zero (a child was reaped).

Example

<?php

$status = 0;
$pid = posix_waitpid(-1, $status, WNOHANG);

posix_hostname(): string|false

Returns the current host name via gethostname(2). Returns false if the syscall fails.

Registered only when posix_hostname() is not already defined.

Example

<?php

$host = posix_hostname();

Quick reference

Helper Signature
posix_open posix_open(string $filepath, int $flags = 2, int $mode = 0644): int
posix_chmod posix_chmod(string $path, int $mode): int
posix_chown posix_chown(string $path, int $owner, int $group): int
posix_fchmod posix_fchmod(int $fd, int $mode): int
posix_fchown posix_fchown(int $fd, int $owner, int $group): int
posix_close posix_close(int $fd): int
posix_write posix_write(int $fd, string $data, int $bytes_to_write): int
posix_read posix_read(int $fd, int $bytes_to_read): string|false
posix_getuid posix_getuid(): int
posix_setuid posix_setuid(int $uid): int
posix_umask posix_umask(int $mask): int
posix_lseek posix_lseek(int $fd, int $offset, int $whence): int
posix_recv posix_recv(int $fd, int $len, int $flags = 0): string|false
posix_readv posix_readv(int $fd, array $iovecs): array|false
fcntl fcntl(int $fd, int $command, mixed $arg, mixed &$value): int
ioctl ioctl(int $fd, int $command, mixed $arg, mixed &$value): int
posix_wait posix_wait(?int &$status = null): int
posix_waitpid posix_waitpid(int $pid, ?int &$status = null, int $options = 0): int
posix_hostname posix_hostname(): string|false

License

MIT. See LICENSE.

About

Bindings for REAL POSIX IO with PHP

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages