FileOutputStream::isLocked()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
/**
4
 * This file is part of the PHP Generics package.
5
 *
6
 * @package Generics
7
 */
8
namespace Generics\Streams;
9
10
use Generics\FileExistsException;
11
use Generics\NoAccessException;
12
use Generics\LockException;
13
use Generics\Lockable;
14
use Generics\ResetException;
15
use Exception;
16
17
/**
18
 * This class provides a file output stream.
19
 *
20
 * @author Maik
21
 */
22
class FileOutputStream implements OutputStream, Lockable
23
{
24
25
    /**
26
     * The file handle
27
     *
28
     * @var resource
29
     */
30
    private $handle;
31
32
    /**
33
     * The absolute file path and name
34
     *
35
     * @var string
36
     */
37
    private $fileName;
38
39
    /**
40
     * Whether resource is locked
41
     *
42
     * @var bool
43
     */
44
    private $locked;
45
46
    /**
47
     * Whether to append
48
     *
49
     * @var bool
50
     */
51
    private $append;
52
53
    /**
54
     * Create a new FileOutputStream
55
     *
56
     * @param string $file
57
     *            The absolute (or relative) path to file to write into.
58
     * @param boolean $append
59
     *            Whether to append the data to an existing file.
60
     * @throws FileExistsException will be thrown in case of file exists and append is set to false.
61
     * @throws NoAccessException will be thrown in case of it is not possible to write to file.
62
     */
63 25
    public function __construct($file, $append = false)
64
    {
65 25
        $this->open($file, $append);
66 24
    }
67
68 25
    private function open($file, $append)
69
    {
70 25
        $this->locked = false;
71
        
72 25
        $mode = "wb";
73
        
74 25
        if (file_exists($file)) {
75 3
            if (! $append) {
76 1
                throw new FileExistsException("File $file already exists!");
77
            }
78
            
79 2
            if (! is_writable($file)) {
80
                throw new NoAccessException("Cannot write to file $file");
81
            }
82 2
            $mode = "ab";
83
        } else {
84 23
            if (! is_writable(dirname($file))) {
85
                throw new NoAccessException("Cannot write to file {file}", array(
86
                    'file' => $file
87
                ));
88
            }
89
        }
90
        
91 24
        $this->handle = fopen($file, $mode);
92
        
93 24
        if (! $this->ready()) {
94
            throw new StreamException("Could not open {file} for writing", array(
95
                'file' => $file
96
            ));
97
        }
98
        
99 24
        $this->fileName = $file;
100 24
        $this->append = $append;
101 24
    }
102
103
    /**
104
     * Cleanup (e.g.
105
     * release lock)
106
     */
107 24
    public function __destruct()
108
    {
109
        try {
110 24
            if ($this->locked) {
111 24
                $this->unlock();
112
            }
113
        } catch (\Generics\GenericsException $ex) {
114
            // Do nothing
115
        }
116 24
    }
117
118
    /**
119
     *
120
     * {@inheritdoc}
121
     * @see \Generics\Streams\Stream::ready()
122
     */
123 24
    public function ready(): bool
124
    {
125 24
        return is_resource($this->handle);
126
    }
127
128
    /**
129
     *
130
     * {@inheritdoc}
131
     * @see \Generics\Streams\OutputStream::write()
132
     */
133 19
    public function write($buffer)
134
    {
135 19
        if (! $this->ready()) {
136
            throw new StreamException("Stream is not open!");
137
        }
138
        
139 19
        if ($buffer instanceof InputStream) {
140 15
            $in = clone $buffer;
141 15
            assert($in instanceof InputStream);
142 15
            while ($in->ready()) {
143 15
                $buf = $in->read(1024);
144 15
                if (fwrite($this->handle, $buf) != strlen($buf)) {
145
                    throw new StreamException("Could not write memory stream into file");
146
                }
147
            }
148
        } else {
149 4
            $buffer = strval($buffer);
150 4
            if (fwrite($this->handle, $buffer) != strlen($buffer)) {
151
                throw new StreamException("Could not write buffer into file");
152
            }
153 4
            fflush($this->handle);
154
        }
155 19
    }
156
157
    /**
158
     *
159
     * {@inheritdoc}
160
     * @see \Generics\Streams\Stream::close()
161
     */
162 21
    public function close()
163
    {
164 21
        if (is_resource($this->handle)) {
165 21
            fclose($this->handle);
166 21
            $this->handle = null;
167
        }
168 21
    }
169
170
    /**
171
     *
172
     * {@inheritdoc}
173
     * @see \Countable::count()
174
     */
175 2
    public function count(): int
176
    {
177 2
        if (! $this->ready()) {
178 1
            throw new StreamException("Stream is not open!");
179
        }
180
        
181 1
        return ftell($this->handle);
182
    }
183
184
    /**
185
     * Retrieve the file path and name
186
     *
187
     * @return string
188
     */
189 1
    public function __toString(): string
190
    {
191 1
        return realpath($this->fileName);
192
    }
193
194
    /**
195
     *
196
     * {@inheritdoc}
197
     * @see \Generics\Streams\OutputStream::isWriteable()
198
     */
199 1
    public function isWriteable(): bool
200
    {
201 1
        return $this->ready();
202
    }
203
204
    /**
205
     *
206
     * {@inheritdoc}
207
     * @see \Generics\Streams\OutputStream::flush()
208
     */
209 16
    public function flush()
210
    {
211 16
        if (! $this->ready()) {
212 1
            throw new StreamException("Stream is not open!");
213
        }
214
        
215 15
        fflush($this->handle);
216 15
    }
217
218
    /**
219
     *
220
     * {@inheritdoc}
221
     * @see \Generics\Lockable::lock()
222
     */
223 3 View Code Duplication
    public function lock()
224
    {
225 3
        if ($this->locked || flock($this->handle, LOCK_EX) === false) {
226 1
            throw new LockException("Could not acquire lock");
227
        }
228 3
        $this->locked = true;
229 3
    }
230
231
    /**
232
     *
233
     * {@inheritdoc}
234
     * @see \Generics\Lockable::unlock()
235
     */
236 4 View Code Duplication
    public function unlock()
237
    {
238 4
        if (! $this->locked || flock($this->handle, LOCK_UN) === false) {
239 1
            throw new LockException("Could not release lock");
240
        }
241 3
        $this->locked = false;
242 3
    }
243
244
    /**
245
     *
246
     * {@inheritdoc}
247
     * @see \Generics\Lockable::isLocked()
248
     */
249 1
    public function isLocked(): bool
250
    {
251 1
        return $this->locked;
252
    }
253
254
    /**
255
     *
256
     * {@inheritdoc}
257
     * @see \Generics\Streams\Stream::isOpen()
258
     */
259
    public function isOpen(): bool
260
    {
261
        return is_resource($this->handle);
262
    }
263
264
    /**
265
     *
266
     * {@inheritdoc}
267
     * @see \Generics\Resettable::reset()
268
     */
269
    public function reset()
270
    {
271
        try {
272
            $this->close();
273
            $this->open($this->fileName, $this->append);
274
        } catch (Exception $ex) {
275
            throw new ResetException($ex->getMessage(), array(), $ex->getCode(), $ex);
276
        }
277
    }
278
}
279