1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Licensed under the MIT license:
* http://opensource.org/licenses/MIT
*/
namespace Icewind\Streams;
/**
* Wrapper that provides callbacks for write, read and close
*
* The following options should be passed in the context when opening the stream
* [
* 'callback' => [
* 'source' => resource
* 'read' => function($count){} (optional)
* 'write' => function($data){} (optional)
* 'close' => function(){} (optional)
* 'readdir' => function(){} (optional)
* ]
* ]
*
* All callbacks are called after the operation is executed on the source stream
*/
class CallbackWrapper extends Wrapper {
/**
* @var callable
*/
protected $readCallback;
/**
* @var callable
*/
protected $writeCallback;
/**
* @var callable
*/
protected $closeCallback;
/**
* @var callable
*/
protected $readDirCallBack;
/**
* Wraps a stream with the provided callbacks
*
* @param resource $source
* @param callable $read (optional)
* @param callable $write (optional)
* @param callable $close (optional)
* @param callable $readDir (optional)
* @return resource
*
* @throws \BadMethodCallException
*/
public static function wrap($source, $read = null, $write = null, $close = null, $readDir = null) {
$context = stream_context_create(array(
'callback' => array(
'source' => $source,
'read' => $read,
'write' => $write,
'close' => $close,
'readDir' => $readDir
)
));
return Wrapper::wrapSource($source, $context, 'callback', '\Icewind\Streams\CallbackWrapper');
}
protected function open() {
$context = $this->loadContext('callback');
$this->readCallback = $context['read'];
$this->writeCallback = $context['write'];
$this->closeCallback = $context['close'];
$this->readDirCallBack = $context['readDir'];
return true;
}
public function dir_opendir($path, $options) {
return $this->open();
}
public function stream_open($path, $mode, $options, &$opened_path) {
return $this->open();
}
public function stream_read($count) {
$result = parent::stream_read($count);
if (is_callable($this->readCallback)) {
call_user_func($this->readCallback, $count);
}
return $result;
}
public function stream_write($data) {
$result = parent::stream_write($data);
if (is_callable($this->writeCallback)) {
call_user_func($this->writeCallback, $data);
}
return $result;
}
public function stream_close() {
$result = parent::stream_close();
if (is_callable($this->closeCallback)) {
call_user_func($this->closeCallback);
// prevent further calls by potential PHP 7 GC ghosts
$this->closeCallback = null;
}
return $result;
}
public function dir_readdir() {
$result = parent::dir_readdir();
if (is_callable($this->readDirCallBack)) {
call_user_func($this->readDirCallBack);
}
return $result;
}
}
|