2012-07-31 15 views
7

için bir test dizisi olarak özel bir akış sarmalayıcısı kullanarak, yerleşik http:// akış sargısını kullanan bir HTTP istemci sınıfı için birim sınamalarında bir saplama olarak kullanmak üzere özel bir akış sarıcısı yazdım.PHP'nin http: // akış sarıcısı

Özel olarak, özel akış sarmalayıcısı tarafından oluşturulan akışlarda stream_get_meta_data numaralı çağrılara yapılan 'wrapper_data' anahtarında döndürülen değer üzerinde denetim ihtiyacım var. Ne yazık ki, özel akış paketleyicileriyle ilgili belgeler kötüye gidiyor ve API beklenmedik görünüyor.

Özel bir sarıcıda hangi yöntem meta wrapper_data yanıtını denetler? Ben özel sargı ile oluşturulan akışlarında var_dump(stream_get_meta_data($stream)); ...

array(10) { 
    'wrapper_data' => 
    class CustomHttpStreamWrapper#5 (3) { 
    public $context => 
    resource(13) of type (stream-context) 
    public $position => 
    int(0) 
    public $bodyData => 
    string(14) "test body data" 
    } 
    ... 

Ama verimli içine sarmalayıcı koaksiyel gerektiğinde altındaki sınıfını kullanma

Sadece şu sonuç almak mümkün oldum gerçek http:// akışı sarmalayıcı tarafından döndürülen verilerin istemci sınıfının ayrıştırmayı test böylece meta veri alma aşağıdaki gibi bir şey ... İşte

array(10) { 
    'wrapper_data' => Array(
     [0] => HTTP/1.1 200 OK 
     [1] => Content-Length: 438 
    ) 
    ... 

Ben özel sarmalayıcı için şu anda sahip kod:

class CustomHttpStreamWrapper { 

    public $context; 
    public $position = 0; 
    public $bodyData = 'test body data'; 

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

    public function stream_read($count) { 
     $this->position += strlen($this->bodyData); 
     if ($this->position > strlen($this->bodyData)) { 
      return false; 
     } 
     return $this->bodyData; 
    } 

    public function stream_eof() { 
     return $this->position >= strlen($this->bodyData); 
    } 

    public function stream_stat() { 
     return array('wrapper_data' => array('test')); 
    } 

    public function stream_tell() { 
     return $this->position; 
    } 
} 
+0

? [Docs] (http://www.php.net/manual/en/streamwrapper.stream-metadata.php) tersi de olsa, yardımcı olabilir. – Christian

+0

Çok iyi niyetlerini onurlandırıyorum! – hakre

cevap

14

stream_get_meta_dataext/standard/streamfunc.c uygulanmaktadır. İlgili parçasıdır

if (stream->wrapperdata) { 
    MAKE_STD_ZVAL(newval); 
    MAKE_COPY_ZVAL(&stream->wrapperdata, newval); 

    add_assoc_zval(return_value, "wrapper_data", newval); 
} 

yani ne olursa olsun zval stream-> wrapperdata $ retval [ "wrapper_data"] tarafından başvurulan/için "kopyalanmış" olduğu tutar.
Özel sarma kodunuz, numaralı telefondan user_wrapper_opener tarafından "işlenir". Ve orada

/* set wrapper data to be a reference to our object */ 
stream->wrapperdata = us->object; 

us->object akışı için örneği olmuştur özel sargının örneği "dir" var. Bunun dışındaki kullanıcı alanı komut dosyalarından stream->wrapperdata'u etkilemenin bir yolunu bulamadım.
Ancak ihtiyacınız olan tek şey foreach($metadata['wrapper_data'] ...) ve ise Iterator/IteratorAggregate ve/veya ArrayAccess uygulayabilirsiniz.
E.g.

<?php 
function test() { 
    stream_wrapper_register("mock", "CustomHttpStreamWrapper") or die("Failed to register protocol"); 
    $fp = fopen("mock://myvar", "r+"); 
    $md = stream_get_meta_data($fp); 

    echo "Iterator/IteratorAggregate\n"; 
    foreach($md['wrapper_data'] as $e) { 
     echo $e, "\n"; 
    } 

    echo "\nArrayAccess\n"; 
    echo $md['wrapper_data'][0], "\n"; 

    echo "\nvar_dump\n"; 
    echo var_dump($md['wrapper_data']); 
} 

class CustomHttpStreamWrapper implements IteratorAggregate, ArrayAccess { 
    public $context; 
    public $position = 0; 
    public $bodyData = 'test body data'; 

    protected $foo = array('HTTP/1.1 200 OK', 'Content-Length: 438', 'foo: bar', 'ham: eggs'); 
    /* IteratorAggregate */ 
    public function getIterator() { 
     return new ArrayIterator($this->foo); 
    } 
    /* ArrayAccess */ 
    public function offsetExists($offset) { return array_key_exists($offset, $this->foo); } 
    public function offsetGet($offset) { return $this->foo[$offset]; } 
    public function offsetSet($offset, $value) { $this->foo[$offset] = $value; } 
    public function offsetUnset($offset) { unset($this->foo[$offset]); } 

    /* StreamWrapper */ 
    public function stream_open($path, $mode, $options, &$opened_path) { 
     return true; 
    } 

    public function stream_read($count) { 
     $this->position += strlen($this->bodyData); 
     if ($this->position > strlen($this->bodyData)) { 
      return false; 
     } 
     return $this->bodyData; 
    } 

    public function stream_eof() { 
     return $this->position >= strlen($this->bodyData); 
    } 

    public function stream_stat() { 
     return array('wrapper_data' => array('test')); 
    } 

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

test(); 

baskılar

Nasıl `streamWrapper :: stream_metadata` hakkında
Iterator/IteratorAggregate 
HTTP/1.1 200 OK 
Content-Length: 438 
foo: bar 
ham: eggs 

ArrayAccess 
HTTP/1.1 200 OK 

var_dump 
object(CustomHttpStreamWrapper)#1 (4) { 
    ["context"]=> 
    resource(5) of type (stream-context) 
    ["position"]=> 
    int(0) 
    ["bodyData"]=> 
    string(14) "test body data" 
    ["foo":protected]=> 
    array(4) { 
    [0]=> 
    string(15) "HTTP/1.1 200 OK" 
    [1]=> 
    string(19) "Content-Length: 438" 
    [2]=> 
    string(8) "foo: bar" 
    [3]=> 
    string(9) "ham: eggs" 
    } 
} 
+0

Çevrelerinde gitmemi sağlayan bir sorun için zarif ve utanç verici basit bir çözüm. Teşekkür ederim. – rdlowrey

+1

Bahse girerim, eğer bu sitede belgelenmiş olsaydı, ben de daireler çizmezdim. – b01