PHP Sessions and Data Persistence
Storing Arbitrary Data in Shared Memory
You want a chunk of data to be available to all server processes through shared memory.
Solution
If you want to share data only amongst PHP processes, use APC, as described in Recipe. If you want to share data with other processes as well, use the pc_Shm class shown in Example.
$shm = new pc_Shm();
$secret_code = 'land shark';
$shm->write('mysecret', strlen($secret_code), $secret_code);
Discussion
Example Storing arbitrary data in shared memory
class pc_Shm {
protected $tmp;
public function __construct($tmp = '') {
if (!function_exists('shmop_open')) {
trigger_error('pc_Shm: shmop extension is required.', E_USER_ERROR);
return;
}
if ($tmp != '' && is_dir($tmp) && is_writable($tmp)) {
$this->tmp = $tmp;
} else {
$this->tmp = '/tmp';
}
}
public function read($id, $size) {
$shm = $this->open($id, $size);
$data = shmop_read($shm, 0, $size);
$this->close($shm);
if (!$data) {
trigger_error('pc_Shm: could not read from shared memory block',
E_USER_ERROR);
return false;
}
return $data;
}
public function write($id, $size, $data) {
$shm = $this->open($id, $size);
$written = shmop_write($shm, $data, 0);
$this->close($shm);
if ($written != strlen($data)) {
trigger_error('pc_Shm: could not write entire length of data',
E_USER_ERROR);
return false;
}
return true;
}
public function delete($id, $size) {
$shm = $this->open($id, $size);
if (shmop_delete($shm)) {
$keyfile = $this->getKeyFile($id);
if (file_exists($keyfile)) {
unlink($keyfile);
}
}
return true;
}
protected function open($id, $size) {
$key = $this->getKey($id);
$shm = shmop_open($key, 'c', 0644, $size);
if (!$shm) {
trigger_error('pc_Shm: could not create shared memory segment',
E_USER_ERROR);
return false;
}
return $shm;
}
protected function close($shm) {
return shmop_close($shm);
}
protected function getKey($id) {
$keyfile = $this->getKeyFile($id);
if (! file_exists($keyfile)) {
touch($keyfile);
}
return ftok($keyfile, 'R');
}
protected function getKeyFile($id) {
return $this->tmp . DIRECTORY_SEPARATOR . 'pcshm_' . $id;
}
}
Because pc_Shm uses standard system functions for accessing shared memory, other programs (no matter what language they’re written in) can access that data as well. For example, shows a short C program that can read data written by pc_Shm.
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
int main(int argc, char **argv) {
char *id;
size_t size;
if (argc != 3) {
fprintf(stderr, "Usage: %s ID SIZE\n", argv[0]);
return -1;
}
id = argv[1];
size = atoi(argv[2]);
char *path;
asprintf(&path, "/tmp/pcshm_%s", id);
key_t token = ftok(path, (int) 'R');
int shmid = shmget(token, size, 0);
void *ptr = shmat(shmid, 0, SHM_RDONLY);
printf("%*s\n", (int) size, (char *) ptr);
shmdt(ptr);
free(path);
}
Compiling that program and then invoking it with arguments mysecret and 10 (or any sufficiently long length) will print the data inserted into shared memory by the PHP code.
It’s important to remember that, unlike setting a key/value pair in a regular PHP array, the shmop functions need to allocate a specific amount of space that the data stored there is expected to consume. That is why the read and write operations require a size to be passed to them.
No comments:
Post a Comment