2011-04-14 15 views
9

Io uso openssl_pkcs7_sign e openssl_pkcs7_encrypt per creare dati crittografati. Le funzioni accettano solo nomi di file. Vorrei memorizzare i file temporanei nella memoria condivisa per migliorare le prestazioni. Capisco in Linux che posso file_put_contents('/dev/shm/xxx', data), ma non è possibile per Windows. C'è un modo portatile in PHP per fare questo? La funzione shmop_ può essere d'aiuto? Grazie.File di memoria condivisa in PHP

PS: O esiste un modo per far accettare queste funzioni alle stringhe di dati?

PS2: Si prega di non suggerire di invocare /usr/bin/openssl da PHP. Non è portatile

+0

cosa vuoi fare con esso una volta salvato? Hai pensato di utilizzare un flusso di file anziché la memoria condivisa? si veda [StreamWrapper] (http://us2.php.net/manual/en/class.streamwrapper.php) – ircmaxell

+0

Ho appena salvato i dati nel file (usando 'file_put_contents') e ho inserito il nome del file nelle funzioni OpenSSL. La maggior parte dell'overhead proviene dalle funzioni OpenSSL e dalle operazioni VFS (lettura, scrittura, scollegamento). In che modo lo streaming fa la differenza? –

risposta

3

Da Windows 2000 sono disponibili i metodi shmop (in precedenza shm_).

shmop_open utilizza un numero intero univoco per condividere l'area di memoria. ftok può essere utilizzato per produrre un indice univoco basato su un percorso file (in genere il percorso completo del file di script). Qualsiasi istanza che condivide la stessa chiave può condividere la stessa memoria.

http://php.net/manual/en/ref.shmop.php

Testato su PHP versione 5.3.3 da Zend Server CE di sistema di Windows NT CRYPE 6.1 Build 7601 (versione Unknow di Windows Business Edition Service Pack 1) i586

<?php 
$key = ftok(__FILE__, 't'); 
$memory = shmop_open($key, "c", 0600, 16 * 1024); 
$data = array('data' => 'value'); 
$bytes = shmop_write($memory, serialize($data), 0); 
$return = shmop_read($memory, 0, $bytes); 
print_r(unserialize($return)); 
?> 

shmop_read/shmop_write negozi byte grezzi da una stringa, quindi non è necessario serializzarli, ma dovrai scrivere la lunghezza della stringa da qualche parte. Il mio esempio crea un'area di memoria condivisa di 16 KB, è ovviamente possibile ridimensionarlo per adattarlo al file openssl e allo spazio necessario per memorizzare le dimensioni del file.

+0

Capisco le funzioni 'shmop_'. La mia domanda è: come si alimenta il nome del file in OpenSSL? I blocchi di memoria non hanno nomi di file. –

+0

Non sembra che la maggior parte delle funzioni di OpenSSL accetti i puntatori di file, il che avrebbe permesso di usare i file di memoria '' php: // memory''. Dovrai utilizzare i file temporanei per leggere i dati dentro e fuori, il che negherebbe tutti i vantaggi della memoria condivisa secondo me. Tuttavia, alcune funzioni come openssl_private_decrypt ti consentono di lavorare con le stringhe anziché con i file, che puoi caricare e scaricare direttamente dalla memoria condivisa. Ci sono altre funzioni MIME che potrebbero funzionare invece di pkcs7, ma non sono così familiare. Consiglierei di guardare se alcune di quelle funzioni funzioneranno per le tue esigenze. –

+0

Inoltre è possibile utilizzare shmop_size per ripristinare la dimensione del blocco. – RafaSashi

6

Ok, quindi il modo in cui suggerirei di farlo è con un file stream wrapper. Mi permetta di montare un rapido esempio:

class staticStreamWrapper { 
    public $context; 
    protected static $data = array(); 

    protected $path = ''; 
    protected $pointer = 0; 
    protected $writable = false; 

    public function stream_close() {} 

    public function stream_eof() { 
     return $this->pointer >= strlen(static::$data[$this->path]); 
    } 

    public function stream_flush() {} 

    public function stream_open($path, $mode, $options, &$opened_path) { 
     switch ($mode[0]) { 
      case 'r': 
       if (!isset(static::$data[$path])) return false; 
       $this->path = $path; 
       $this->writable = isset($mode[1]) && $mode[1] == '+'; 
       break; 
      case 'w': 
       static::$data[$path] = ''; 
       $this->path = $path; 
       $this->writable = true; 
       break; 
      case 'a': 
       if (!isset(static::$data[$path])) static::$data[$path] = ''; 
       $this->path = $path; 
       $this->writable = true; 
       $this->pointer = strlen(static::$data[$path]); 
       break; 
      case 'x': 
       if (isset(static::$data[$path])) return false; 
       $this->path = $path; 
       $this->writable = true; 
       break; 
      case 'c': 
       if (!isset(static::$data[$path])) static::$data[$path] = ''; 
       $this->path = $path; 
       $this->writable = true; 
       break; 
      default: 
       return false; 
     } 
     $opened_path = $this->path; 
     return true; 
    } 

    public function stream_read($count) { 
     $bytes = min(strlen(static::$data[$this->path]) - $this->pointer, $count); 
     $data = substr(static::$data[$this->path], $this->pointer, $bytes); 
     $this->pointer += $bytes; 
     return $data; 
    } 

    public function stream_seek($offset, $whence = SEEK_SET) { 
     $len = strlen(static::$data[$this->path]); 
     switch ($whence) { 
      case SEEK_SET: 
       if ($offset <= $len) { 
        $this->pointer = $offset; 
        return true; 
       } 
       break; 
      case SEEK_CUR: 
       if ($this->pointer + $offset <= $len) { 
        $this->pointer += $offset; 
        return true; 
       } 
       break; 
      case SEEK_END: 
       if ($len + $offset <= $len) { 
        $this->pointer = $len + $offset; 
        return true; 
       } 
       break; 
     } 
     return false; 
    } 

    public function stream_stat() { 
     $size = strlen(static::$data[$this->path]); 
     $time = time(); 
     return array(
      0 => 0, 
      'dev' => 0, 
      1 => 0, 
      'ino' => 0, 
      2 => 0777, 
      'mode' => 0777, 
      3 => 1, 
      'nlink' => 1, 
      4 => 0, 
      'uid' => 0, 
      5 => 0, 
      'gid' => 0, 
      6 => '', 
      'rdev' => '', 
      7 => $size, 
      'size' => $size, 
      8 => $time, 
      'atime' => $time, 
      9 => $time, 
      'mtime' => $time, 
      10 => $time, 
      'ctime' => $time, 
      11 => -1, 
      'blksize' => -1, 
      12 => -1, 
      'blocks' => -1, 
     ); 
    } 

    public function stream_tell() { 
     return $this->pointer; 
    } 

    public function stream_write($data) { 
     if (!$this->writable) return 0; 
     $size = strlen($data); 
     $len = strlen(static::$data[$this->path]); 
     if ($this->stream_eof()) { 
      static::$data[$this->path] .= $data; 
     } else { 
      static::$data[$this->path] = substr_replace(
       static::$data[$this->path], 
       $data, 
       $this->pointer 
      ); 
     } 
     $this->pointer += $size; 
     return $size; 
    } 

    public function unlink($path) { 
     if (isset(static::$data[$path])) { 
      unset(static::$data[$path]); 
     } 
     return true; 
    } 

} 

Ora, si sarebbe poi necessario registrare il wrapper:

stream_wrapper_register('static', 'staticStreamWrapper'); 

Quindi è ora possibile trattarlo come un file, anche se mai realmente lascia PHP (è memorizzato come variabile statica)!

file_put_contents('static://foo.txt', 'this is my data'); 
file_get_contents('static://foo.txt'); // "this is my data" 
$f = fopen('static://foo.txt', 'r'); // should return a resource 
// etc... 
+0

Grazie per le informazioni sul flusso.Capisco che PHP supporti l'implementazione del wrapper stream personalizzato. Tuttavia, l'estensione OpenSSL è molto probabilmente scritta con le API del sistema operativo e le funzioni non utilizzano gli stream PHP. La chiamata di 'openssl_pkcs7_encrypt' con stream' static' restituisce il seguente messaggio di errore: 'errore: 02001002: libreria di sistema: fopen: nessun file o directory'. –

Problemi correlati