2016-05-31 28 views
5

Próbuję utworzyć plik "wirtualny" bez użycia pamięci lub pliku tymczasowego. Plik "wirtualny" musi przejść test sprawdzany za pomocą file_exists(), nie rzucając żadnego błędu ani ostrzeżenia, gdy jest używany z require lub include.Jak utworzyć fałszywy/"wirtualny" plik?

Pozwala realizować własne obsługi protokołów i strumieni do użytku z all the other filesystem functions (takich jak fopen(), fread() itd.).

... gdzie file_exists() jest jednym z nich. The docs page states:

Począwszy od PHP 5.0.0, ta funkcja może być również używana w niektórych opakowaniach adresów URL. Zapoznaj się z numerem Supported Protocols and Wrappers, aby ustalić, które opakowania obsługują rodzinę funkcji stat().

Moja próba była zbudować zwyczaj, wirtualny plik opakowanie

class VirtualFileWrapper 
{ 
    public $context; 

    public function stream_open($path, $mode, $options, &$opened_path) 
    { 
     return TRUE; 
    } 

    public function stream_stat() 
    { 
     var_dump(__METHOD__); 
     $data = [ 
      'dev'  => 0, 
      'ino'  => getmyinode(), 
      'mode' => 'r', 
      'nlink' => 0, 
      'uid'  => getmyuid(), 
      'gid'  => getmygid(), 
      'rdev' => 0, 
      'size' => 0, 
      'atime' => time(), 
      'mtime' => getlastmod(), 
      'ctime' => FALSE, 
      'blksize' => 0, 
      'blocks' => 0, 
     ]; 
     return array_merge(array_values($data), $data); 
    } 
} 

stream_wrapper_register('virtual', 'VirtualFileWrapper'); 

$file = fopen("virtual://foo", 'r+'); 

// Executes VirtualFileWrapper::stream_stat() 
fstat($file); 

// Executes no VirtualFileWrapper method 
file_exists($file); 

Chociaż funkcja fstat() wykonuje metodę, file_exists() nie wykonuje żadnej metody klasy strumień.

Jak mogę uruchomić opakowanie wirtualnego strumienia (z file_exists())?


Jestem w pełni świadomy, że tempnam(__DIR__, '') przejdzie obie:

  • var_dump(tempnam(__DIR__, '')); Returns true
  • require tempnam(__DIR__, ''); Brak błędu

ale nie chcę użyć pliku tymczasowego, ponieważ nie może być lepszy sposób (pod względem wydajności).

+1

Nie możesz. file_exists() oczekuje, że łańcuch będzie jego argumentem. Możesz przekazać obiekt, który implementuje magiczną metodę __toString(), ale wtedy file_exists użyje 'stat()' tego łańcucha i zawodzi, ponieważ plik tak naprawdę nie istnieje. –

+0

@MarcB Faktycznie [** Drupal ** ma to działające] (http://drupal.stackexchange.com/a/24233/55237). Po prostu nie mogłem naprawdę dowiedzieć się, jak rzeczy 'vfsStream' są po prostu zawalone w źródle. – kaiser

+0

Dlaczego próbujesz to osiągnąć? Myślę, że tworzenie fałszywego pliku jest bardzo dziwną praktyką. – Jehy

Odpowiedz

5

Wygląda na to, że wystarczy wdrożyć publiczną metodę url_stat() na VirtualFileWrapper, aby pomyślnie przejść test file_exists().

Aby wyciszyć ostrzeżenia i błędy z include i require, należy wdrożyć stream_read() i stream_eof() metod:

class VirtualFileWrapper 
{ 
    public $context; 

    public function stream_open($path, $mode, $options, &$opened_path) 
    { 
     return TRUE; 
    } 

    public function stream_stat() 
    { 
     var_dump(__METHOD__); 
     return []; 
    } 

    public function url_stat() 
    { 
     return array (
      0 => 0, 
      1 => 0, 
      2 => 0, 
      3 => 0, 
      4 => 0, 
      5 => 0, 
      6 => 0, 
      7 => 0, 
      8 => 0, 
      9 => 0, 
      10 => 0, 
      11 => 0, 
      12 => 0, 
      'dev' => 0, 
      'ino' => 0, 
      'mode' => 0, 
      'nlink' => 0, 
      'uid' => 0, 
      'gid' => 0, 
      'rdev' => 0, 
      'size' => 0, 
      'atime' => 0, 
      'mtime' => 0, 
      'ctime' => 0, 
      'blksize' => 0, 
      'blocks' => 0 
     ); 
    } 

    public function stream_read(){ 
     return ''; 
    } 

    public function stream_eof(){ 
     return ''; 
    } 

} 

stream_wrapper_register('virtual', 'VirtualFileWrapper'); 

$file = fopen("virtual://foo", 'r+'); 

// Executes VirtualFileWrapper::stream_stat() 
fstat($file); 

// Executes no VirtualFileWrapper method 
file_exists("virtual://foo"); 

//Still no errors :-)! 
require "virtual://foo"; 
include "virtual://foo"; 

Zadbaj przekazać file_exists() ciąg, zamiast utworzoną z fopen() zasobu.

+0

Chciałbym podać więcej szczegółów - nie mam pojęcia, dlaczego to działa, wrócę i edytuję, jeśli się zorientuję. – HPierce

+0

Po tych kilku godzinach bardzo się cieszę, że wskoczyłeś: Mój przykład był bliski różnicy od twojego, poza tym, że zwróciłem 'stat()' wewnątrz 'url_stat()'. Wygląda na to, że muszę nauczyć się czytać: P [Zwróć wartość] (http://php.net/manual/en/streamwrapper.url-stat.php) jasno to stwierdza. Dzięki za tonę! Btw, kolejną dziwną rzeczą jest to, że zarówno 'require' jak' include' nazywane _twice_ w moim teście lokalnym. – kaiser