AbstractStreamWrapper::stream_read()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
crap 2
1
<?php
2
/*
3
 * Copyright (C) 2017 by TEQneers GmbH & Co. KG
4
 *
5
 * Permission is hereby granted, free of charge, to any person obtaining a copy
6
 * of this software and associated documentation files (the "Software"), to deal
7
 * in the Software without restriction, including without limitation the rights
8
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the Software is
10
 * furnished to do so, subject to the following conditions:
11
 *
12
 * The above copyright notice and this permission notice shall be included in
13
 * all copies or substantial portions of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
 * THE SOFTWARE.
22
 */
23
24
/**
25
 * Git Stream Wrapper for PHP
26
 *
27
 * @category   TQ
28
 * @package    TQ_VCS
29
 * @subpackage VCS
30
 * @copyright  Copyright (C) 2018 by TEQneers GmbH & Co. KG
31
 */
32
33
namespace TQ\Vcs\StreamWrapper;
34
use TQ\Vcs\Buffer\ArrayBuffer;
35
use TQ\Vcs\Buffer\FileBufferInterface;
36
use TQ\Vcs\StreamWrapper\FileBuffer\FactoryInterface;
37
38
/**
39
 * A basic abstract stream wrapper that hooks into PHP's stream infrastructure
40
 *
41
 * @author     Stefan Gehrig <gehrigteqneers.de>
42
 * @category   TQ
43
 * @package    TQ_VCS
44
 * @subpackage VCS
45
 * @copyright  Copyright (C) 2018 by TEQneers GmbH & Co. KG
46
 */
47
abstract class AbstractStreamWrapper
48
{
49
    /**
50
     * The registered protocol
51
     *
52
     * @var string
53
     */
54
    protected static $protocol;
55
56
    /**
57
     * The path factory
58
     *
59
     * @var PathFactoryInterface
60
     */
61
    protected static $pathFactory;
62
63
    /**
64
     * The buffer factory
65
     *
66
     * @var FactoryInterface
67
     */
68
    protected static $bufferFactory;
69
70
    /**
71
     * The directory buffer if used on a directory
72
     *
73
     * @var ArrayBuffer
74
     */
75
    protected $dirBuffer;
76
77
    /**
78
     * The file buffer if used on a file
79
     *
80
     * @var FileBufferInterface
81
     */
82
    protected $fileBuffer;
83
84
    /**
85
     * The opened path
86
     *
87
     * @var PathInformationInterface
88
     */
89
    protected $path;
90
91
    /**
92
     * The stream context if set
93
     *
94
     * @var resource
95
     */
96
    public $context;
97
98
    /**
99
     * The parsed stream context options
100
     *
101
     * @var array
102
     */
103
    protected $contextOptions;
104
105
    /**
106
     * The parsed stream context parameters
107
     *
108
     * @var array
109
     */
110
    protected $contextParameters;
111
112
    /**
113
     * Registers the stream wrapper with the given protocol
114
     *
115
     * @param   string                $protocol         The protocol (such as "vcs")
116
     * @param   PathFactoryInterface  $pathFactory      The path factory
117
     * @param   FactoryInterface      $bufferFactory    The buffer factory
118
     * @throws  \RuntimeException                       If $protocol is already registered
119
     */
120 116
    protected static function doRegister($protocol, PathFactoryInterface $pathFactory, FactoryInterface $bufferFactory)
121
    {
122 116
        static::$protocol       = $protocol;
123 116
        static::$pathFactory    = $pathFactory;
124 116
        static::$bufferFactory  = $bufferFactory;
125
126 116
        if (!stream_wrapper_register($protocol, get_called_class())) {
127
            throw new \RuntimeException(sprintf('The protocol "%s" is already registered with the
128
                runtime or it cannot be registered', $protocol));
129
        }
130 116
    }
131
132
    /**
133
     * Unregisters the stream wrapper
134
     */
135 116
    public static function unregister()
136
    {
137 116
        if (!static::$protocol) {
138
            return;
139
        }
140 116
        if (!stream_wrapper_unregister(static::$protocol)) {
141
            throw new \RuntimeException(sprintf('The protocol "%s" cannot be unregistered
142
                from the runtime', static::$protocol));
143
        }
144 116
        static::$protocol       = null;
145 116
        static::$pathFactory    = null;
146 116
        static::$bufferFactory  = null;
147 116
    }
148
149
    /**
150
     * Returns the repository registry
151
     *
152
     * @return  RepositoryRegistry
153
     */
154 12
    public static function getRepositoryRegistry()
155
    {
156 12
        return static::$pathFactory->getRegistry();
157
    }
158
159
    /**
160
     * Returns the path information for a given stream URL
161
     *
162
     * @param   string  $streamUrl          The URL given to the stream function
163
     * @return  PathInformationInterface    The path information representing the stream URL
164
     */
165 114
    protected function getPath($streamUrl)
166
    {
167 114
        return self::$pathFactory->createPathInformation($streamUrl);
168
    }
169
170
    /**
171
     * Creates the buffer factory
172
     *
173
     * @return  FactoryInterface
174
     */
175 52
    protected function getBufferFactory()
176
    {
177 52
        return self::$bufferFactory;
178
    }
179
180
    /**
181
     * Parses the passed stream context and returns the context options
182
     * relevant for this stream wrapper
183
     *
184
     * @param   boolean $all    Return all options instead of just the relevant options
185
     * @return  array           The context options
186
     */
187 42
    protected function getContextOptions($all = false)
188
    {
189 42
        if ($this->contextOptions === null) {
190 42
            $this->contextOptions   = stream_context_get_options($this->context);
191
        }
192
193 42
        if (!$all && array_key_exists(self::$protocol, $this->contextOptions)) {
194 10
            return $this->contextOptions[self::$protocol];
195 32
        } else if ($all) {
196
            return $this->contextOptions;
197
        } else {
198 32
            return array();
199
        }
200
    }
201
202
    /**
203
     * Returns a context option - $default if option is not found
204
     *
205
     * @param   string  $option     The option to retrieve
206
     * @param   mixed   $default    The default value if $option is not found
207
     * @return  mixed
208
     */
209 42
    protected function getContextOption($option, $default = null)
210
    {
211 42
        $options    = $this->getContextOptions();
212 42
        if (array_key_exists($option, $options)) {
213 10
            return $options[$option];
214
        } else {
215 32
            return $default;
216
        }
217
    }
218
219
    /**
220
     * Parses the passed stream context and returns the context parameters
221
     *
222
     * @return  array       The context parameters
223
     */
224
    protected function getContextParameters()
225
    {
226
        if ($this->contextParameters === null) {
227
            $this->contextParameters    = stream_context_get_params($this->context);
228
        }
229
        return $this->contextParameters;
230
    }
231
232
    /**
233
     * Returns a context parameter - $default if parameter is not found
234
     *
235
     * @param   string  $parameter  The parameter to retrieve
236
     * @param   mixed   $default    The default value if $parameter is not found
237
     * @return  mixed
238
     */
239
    protected function getContextParameter($parameter, $default = null)
240
    {
241
        $parameters    = $this->getContextParameters();
242
        if (array_key_exists($parameter, $parameters)) {
243
            return $parameters[$parameter];
244
        } else {
245
            return $default;
246
        }
247
    }
248
249
    /**
250
     * streamWrapper::dir_closedir — Close directory handle
251
     *
252
     * @return  boolean     Returns TRUE on success or FALSE on failure.
253
     */
254 18
    public function dir_closedir()
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::dir_closedir" is not in camel caps format
Loading history...
255
    {
256 18
        $this->dirBuffer    = null;
257 18
        $this->path         = null;
258 18
        return true;
259
    }
260
261
    /**
262
     * streamWrapper::dir_opendir — Open directory handle
263
     *
264
     * @param   string   $path      Specifies the URL that was passed to {@see opendir()}.
265
     * @param   integer  $options   Whether or not to enforce safe_mode (0x04).
266
     * @return  boolean             Returns TRUE on success or FALSE on failure.
267
     */
268 18
    public function dir_opendir($path, $options)
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Coding Style introduced by
Method name "AbstractStreamWrapper::dir_opendir" is not in camel caps format
Loading history...
269
    {
270
        try {
271 18
            $path               = $this->getPath($path);
272 18
            $repo               = $path->getRepository();
273 18
            $listing            = $repo->listDirectory($path->getLocalPath(), $path->getRef());
274 18
            $this->dirBuffer    = new ArrayBuffer($listing);
275 18
            $this->path         = $path;
276 18
            return true;
277
        } catch (\Exception $e) {
278
            trigger_error($e->getMessage(), E_USER_WARNING);
279
            return false;
280
        }
281
    }
282
283
    /**
284
     * streamWrapper::dir_readdir — Read entry from directory handle
285
     *
286
     * @return  string|false    Should return string representing the next filename, or FALSE if there is no next file.
287
     */
288 18
    public function dir_readdir()
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::dir_readdir" is not in camel caps format
Loading history...
289
    {
290 18
        $file   = $this->dirBuffer->current();
291 18
        $this->dirBuffer->next();
292 18
        return $file;
293
    }
294
295
    /**
296
     * streamWrapper::dir_rewinddir — Rewind directory handle
297
     *
298
     * @return  boolean     Returns TRUE on success or FALSE on failure.
299
     */
300 6
    public function dir_rewinddir()
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::dir_rewinddir" is not in camel caps format
Loading history...
301
    {
302 6
        $this->dirBuffer->rewind();
303 6
        return true;
304
    }
305
306
    /**
307
     * streamWrapper::mkdir — Create a directory
308
     *
309
     * @param   string   $path      Directory which should be created.
310
     * @param   integer  $mode      The value passed to {@see mkdir()}.
311
     * @param   integer  $options   A bitwise mask of values, such as STREAM_MKDIR_RECURSIVE.
312
     * @return  boolean             Returns TRUE on success or FALSE on failure.
313
     */
314 12
    public function mkdir($path, $mode, $options)
315
    {
316
        try {
317 12
            $path   = $this->getPath($path);
318 12
            if ($path->getRef() != 'HEAD') {
319 2
                throw new \Exception(sprintf(
320 2
                    'Cannot create a non-HEAD directory [%s#%s]', $path->getFullPath(), $path->getRef()
321
                ));
322
            }
323 10
            if (file_exists($path->getFullPath())) {
324 2
                throw new \Exception(sprintf('Path %s already exists', $path->getFullPath()));
325
            }
326
327 8
            $recursive  = self::maskHasFlag($options, STREAM_MKDIR_RECURSIVE);
328
329 8
            $repo   = $path->getRepository();
330
331 8
            $commitMsg      = $this->getContextOption('commitMsg', null);
332 8
            $author         = $this->getContextOption('author', null);
333
334 8
            $repo->createDirectory($path->getLocalPath(), $commitMsg, $mode, $recursive, $author);
335 6
            return true;
336 6
        } catch (\Exception $e) {
337 6
            trigger_error($e->getMessage(), E_USER_WARNING);
338
            return false;
339
        }
340
    }
341
342
    /**
343
     * streamWrapper::rename — Renames a file or directory
344
     *
345
     * @param   string   $path_from     The URL to the current file.
346
     * @param   string   $path_to       The URL which the $path_from should be renamed to.
347
     * @return  boolean                 Returns TRUE on success or FALSE on failure.
348
     */
349 10
    public function rename($path_from, $path_to)
350
    {
351
        try {
352 10
            $pathFrom   = $this->getPath($path_from);
353 10
            if ($pathFrom->getRef() != 'HEAD') {
354 2
                throw new \Exception(sprintf(
355 2
                    'Cannot rename a non-HEAD file [%s#%s]', $pathFrom->getFullPath(), $pathFrom->getRef()
356
                ));
357
            }
358 8
            if (!file_exists($pathFrom->getFullPath())) {
359 2
                throw new \Exception(sprintf('Path %s not found', $pathFrom->getFullPath()));
360
            }
361
362 6
            if (!is_file($pathFrom->getFullPath())) {
363 2
                throw new \Exception(sprintf('Path %s is not a file', $pathFrom->getFullPath()));
364
            }
365
366 4
            $pathTo = self::$pathFactory->parsePath($path_to);
367 4
            $pathTo = $pathTo['path'];
368
369 4
            if (strpos($pathTo, $pathFrom->getRepositoryPath()) !== 0) {
370
                throw new \Exception(sprintf('Cannot rename across repositories [%s -> %s]',
371
                    $pathFrom->getFullPath(), $pathTo));
372
            }
373
374 4
            $repo   = $pathFrom->getRepository();
375
376 4
            $commitMsg      = $this->getContextOption('commitMsg', null);
377 4
            $author         = $this->getContextOption('author', null);
378
379 4
            $repo->renameFile($pathFrom->getLocalPath(), $pathTo, $commitMsg, false, $author);
380 4
            return true;
381 6
        } catch (\Exception $e) {
382 6
            trigger_error($e->getMessage(), E_USER_WARNING);
383
            return false;
384
        }
385
    }
386
387
    /**
388
     * streamWrapper::rmdir — Removes a directory
389
     *
390
     * @param   string   $path      The directory URL which should be removed.
391
     * @param   integer  $options   A bitwise mask of values, such as STREAM_MKDIR_RECURSIVE.
392
     * @return  boolean             Returns TRUE on success or FALSE on failure.
393
     */
394 10
    public function rmdir($path, $options)
395
    {
396
        try {
397 10
            $path   = $this->getPath($path);
398 10
            if ($path->getRef() != 'HEAD') {
399 2
                throw new \Exception(sprintf(
400 2
                    'Cannot remove a non-HEAD directory [%s#%s]', $path->getFullPath(), $path->getRef()
401
                ));
402
            }
403 8
            if (!file_exists($path->getFullPath())) {
404 2
                throw new \Exception(sprintf('Path %s not found', $path->getFullPath()));
405
            }
406 6
            if (!is_dir($path->getFullPath())) {
407 2
                throw new \Exception(sprintf('Path %s is not a directory', $path->getFullPath()));
408
            }
409
410 4
            $options    |= STREAM_MKDIR_RECURSIVE;
411 4
            $recursive  = self::maskHasFlag($options, STREAM_MKDIR_RECURSIVE);
412
413 4
            $repo   = $path->getRepository();
414
415 4
            $commitMsg      = $this->getContextOption('commitMsg', null);
416 4
            $author         = $this->getContextOption('author', null);
417
418 4
            $repo->removeFile($path->getLocalPath(), $commitMsg, $recursive, false, $author);
419 4
            return true;
420 6
        } catch (\Exception $e) {
421 6
            trigger_error($e->getMessage(), E_USER_WARNING);
422
            return false;
423
        }
424
    }
425
426
    /**
427
     * streamWrapper::stream_cast — Retrieve the underlaying resource
428
     *
429
     * @param   integer  $cast_as   Can be STREAM_CAST_FOR_SELECT when stream_select() is calling stream_cast()
430
     *                              or STREAM_CAST_AS_STREAM when stream_cast() is called for other uses.
431
     * @return  resource            Should return the underlying stream resource used by the wrapper, or FALSE.
432
     */
433
/*
434
    abstract public function stream_cast($cast_as);
435
*/
436
437
    /**
438
     * streamWrapper::stream_close — Close an resource
439
     */
440 50
    public function stream_close()
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::stream_close" is not in camel caps format
Loading history...
441
    {
442 50
        $this->fileBuffer->close();
443 50
        $this->fileBuffer   = null;
444
445 50
        $repo   = $this->path->getRepository();
446 50
        if ($repo->isDirty()) {
447 22
            $repo->add(array($this->path->getFullPath()));
448 22
            $commitMsg      = $this->getContextOption('commitMsg', null);
449 22
            $author         = $this->getContextOption('author', null);
450 22
            $repo->commit($commitMsg, array($this->path->getFullPath()), $author);
451
        }
452
453 50
        $this->path         = null;
454 50
    }
455
456
    /**
457
     * streamWrapper::stream_eof — Tests for end-of-file on a file pointer
458
     *
459
     * @return  boolean     Should return TRUE if the read/write position is at the end of the stream
460
     *                      and if no more data is available to be read, or FALSE otherwise.
461
     */
462 30
    public function stream_eof()
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::stream_eof" is not in camel caps format
Loading history...
463
    {
464 30
        return $this->fileBuffer->isEof();
465
    }
466
467
    /**
468
     * streamWrapper::stream_flush — Flushes the output
469
     *
470
     * @return  boolean     Should return TRUE if the cached data was successfully stored
471
     *                      (or if there was no data to store), or FALSE if the data could not be stored.
472
     */
473 22
    public function stream_flush()
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::stream_flush" is not in camel caps format
Loading history...
474
    {
475 22
        return $this->fileBuffer->flush();
476
    }
477
478
    /**
479
     * streamWrapper::stream_lock — Advisory file locking
480
     *
481
     * @param   integer  $operation     operation is one of the following:
482
     *                                      LOCK_SH to acquire a shared lock (reader).
483
     *                                      LOCK_EX to acquire an exclusive lock (writer).
484
     *                                      LOCK_UN to release a lock (shared or exclusive).
485
     *                                      LOCK_NB if you don't want flock() to block while locking. (not supported on Windows)
486
     * @return  boolean                 Returns TRUE on success or FALSE on failure.
487
     */
488
/*
489
    abstract public function stream_lock($operation);
490
*/
491
492
    /**
493
     * streamWrapper::stream_metadata — Change stream options
494
     *
495
     * @param   string   $path      The file path or URL to set metadata. Note that in the case of a URL,
496
     *                              it must be a :// delimited URL. Other URL forms are not supported.
497
     * @param   integer  $option    One of:
498
     *                                  PHP_STREAM_META_TOUCH (The method was called in response to touch())
499
     *                                  PHP_STREAM_META_OWNER_NAME (The method was called in response to chown() with string parameter)
500
     *                                  PHP_STREAM_META_OWNER (The method was called in response to chown())
501
     *                                  PHP_STREAM_META_GROUP_NAME (The method was called in response to chgrp())
502
     *                                  PHP_STREAM_META_GROUP (The method was called in response to chgrp())
503
     *                                  PHP_STREAM_META_ACCESS (The method was called in response to chmod())
504
     * @param   integer  $var       If option is
505
     *                                  PHP_STREAM_META_TOUCH: Array consisting of two arguments of the touch() function.
506
     *                                  PHP_STREAM_META_OWNER_NAME or PHP_STREAM_META_GROUP_NAME: The name of the owner
507
     *                                      user/group as string.
508
     *                                  PHP_STREAM_META_OWNER or PHP_STREAM_META_GROUP: The value owner user/group argument as integer.
509
     *                                  PHP_STREAM_META_ACCESS: The argument of the chmod() as integer.
510
     * @return  boolean             Returns TRUE on success or FALSE on failure. If option is not implemented, FALSE should be returned.
511
     */
512
/*
513
    abstract public function stream_metadata($path, $option, $var);
514
*/
515
516
    /**
517
     * streamWrapper::stream_open — Opens file or URL
518
     *
519
     * @param   string   $path          Specifies the URL that was passed to the original function.
520
     * @param   string   $mode          The mode used to open the file, as detailed for fopen().
521
     * @param   integer  $options       Holds additional flags set by the streams API. It can hold one or more of
522
     *                                      the following values OR'd together.
523
     *                                      STREAM_USE_PATH         If path is relative, search for the resource using
524
     *                                                              the include_path.
525
     *                                      STREAM_REPORT_ERRORS    If this flag is set, you are responsible for raising
526
     *                                                              errors using trigger_error() during opening of the
527
     *                                                              stream. If this flag is not set, you should not raise
528
     *                                                              any errors.
529
     * @param   string   $opened_path   If the path is opened successfully, and STREAM_USE_PATH is set in options, opened_path
530
     *                                  should be set to the full path of the file/resource that was actually opened.
531
     * @return  boolean                 Returns TRUE on success or FALSE on failure.
532
     */
533 52
    public function stream_open($path, $mode, $options, &$opened_path)
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::stream_open" is not in camel caps format
Loading history...
534
    {
535
        try {
536 52
            $path   = $this->getPath($path);
537
538 52
            $factory            = $this->getBufferFactory();
539 52
            $this->fileBuffer   = $factory->createFileBuffer($path, $mode);
540 50
            $this->path         = $path;
541
542 50
            if (self::maskHasFlag($options, STREAM_USE_PATH)) {
543
                $opened_path    = $this->path->getUrl();
544
            }
545
546 50
            return true;
547 3
        } catch (\Exception $e) {
548 3
            if (self::maskHasFlag($options, STREAM_REPORT_ERRORS)) {
549
                trigger_error($e->getMessage(), E_USER_WARNING);
550
            }
551 3
            return false;
552
        }
553
    }
554
555
    /**
556
     * streamWrapper::stream_read — Read from stream
557
     *
558
     * @param   integer  $count     How many bytes of data from the current position should be returned.
559
     * @return  string              If there are less than count bytes available, return as many as are available.
560
     *                              If no more data is available, return either FALSE or an empty string.
561
     */
562 30
    public function stream_read($count)
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::stream_read" is not in camel caps format
Loading history...
563
    {
564 30
        $buffer = $this->fileBuffer->read($count);
565 30
        if ($buffer === null) {
566 8
            return false;
567
        }
568 30
        return $buffer;
569
    }
570
571
    /**
572
     * streamWrapper::stream_seek — Seeks to specific location in a stream
573
     *
574
     * @param   integer  $offset    The stream offset to seek to.
575
     * @param   integer  $whence    Possible values:
576
     *                                  SEEK_SET - Set position equal to offset bytes.
577
     *                                  SEEK_CUR - Set position to current location plus offset.
578
     *                                  SEEK_END - Set position to end-of-file plus offset.
579
     * @return  boolean             Return TRUE if the position was updated, FALSE otherwise.
580
     */
581 12
    public function stream_seek($offset, $whence = SEEK_SET)
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::stream_seek" is not in camel caps format
Loading history...
582
    {
583 12
        return $this->fileBuffer->setPosition($offset, $whence);
584
    }
585
586
    /**
587
     * streamWrapper::stream_set_option
588
     *
589
     * @param   integer  $option    One of:
590
     *                                  STREAM_OPTION_BLOCKING (The method was called in response to stream_set_blocking())
591
     *                                  STREAM_OPTION_READ_TIMEOUT (The method was called in response to stream_set_timeout())
592
     *                                  STREAM_OPTION_WRITE_BUFFER (The method was called in response to stream_set_write_buffer())
593
     * @param   integer  $arg1      If option is
594
     *                                  STREAM_OPTION_BLOCKING: requested blocking mode (1 meaning block 0 not blocking).
595
     *                                  STREAM_OPTION_READ_TIMEOUT: the timeout in seconds.
596
     *                                  STREAM_OPTION_WRITE_BUFFER: buffer mode (STREAM_BUFFER_NONE or STREAM_BUFFER_FULL).
597
     * @param   integer  $arg2      If option is
598
     *                                  STREAM_OPTION_BLOCKING: This option is not set.
599
     *                                  STREAM_OPTION_READ_TIMEOUT: the timeout in microseconds.
600
     *                                  STREAM_OPTION_WRITE_BUFFER: the requested buffer size.
601
     * @return  boolean             Returns TRUE on success or FALSE on failure. If option is not implemented,
602
     *                              FALSE should be returned.
603
     */
604
/*
605
    abstract public function stream_set_option($option, $arg1, $arg2);
606
*/
607
608
    /**
609
     * streamWrapper::stream_stat — Retrieve information about a file resource
610
     *
611
     * @return  array       stat() and fstat() result format
612
     *                      Numeric     Associative (since PHP 4.0.6)   Description
613
     *                      0           dev                             device number
614
     *                      1           ino                             inode number *
615
     *                      2           mode                            inode protection mode
616
     *                      3           nlink                           number of links
617
     *                      4           uid                             userid of owner *
618
     *                      5           gid                             groupid of owner *
619
     *                      6           rdev                            device type, if inode device
620
     *                      7           size                            size in bytes
621
     *                      8           atime                           time of last access (Unix timestamp)
622
     *                      9           mtime                           time of last modification (Unix timestamp)
623
     *                      10          ctime                           time of last inode change (Unix timestamp)
624
     *                      11          blksize                         blocksize of filesystem IO **
625
     *                      12          blocks                          number of 512-byte blocks allocated **
626
     *                      * On Windows this will always be 0.
627
     *                      ** Only valid on systems supporting the st_blksize type - other systems (e.g. Windows) return -1.
628
     */
629 22
    public function stream_stat()
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::stream_stat" is not in camel caps format
Loading history...
630
    {
631 22
        return $this->fileBuffer->getStat();
632
    }
633
634
    /**
635
     * streamWrapper::stream_tell — Retrieve the current position of a stream
636
     *
637
     * @return  integer     Should return the current position of the stream.
638
     */
639 12
    public function stream_tell()
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::stream_tell" is not in camel caps format
Loading history...
640
    {
641 12
        return $this->fileBuffer->getPosition();
642
    }
643
644
    /**
645
     * streamWrapper::stream_write — Write to stream
646
     *
647
     * @param   string  $data   Should be stored into the underlying stream.
648
     * @return  integer         Should return the number of bytes that were successfully stored, or 0 if none could be stored.
649
     */
650 22
    public function stream_write($data)
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::stream_write" is not in camel caps format
Loading history...
651
    {
652 22
        return $this->fileBuffer->write($data);
653
    }
654
655
    /**
656
     * streamWrapper::unlink — Delete a file
657
     *
658
     * @param   string   $path  The file URL which should be deleted.
659
     * @return  boolean         Returns TRUE on success or FALSE on failure.
660
     */
661 10
    public function unlink($path)
662
    {
663
        try {
664 10
            $path   = $this->getPath($path);
665 10
            if ($path->getRef() != 'HEAD') {
666 2
                throw new \Exception(sprintf(
667 2
                    'Cannot unlink a non-HEAD file [%s#%s]', $path->getFullPath(), $path->getRef()
668
                ));
669
            }
670 8
            if (!file_exists($path->getFullPath())) {
671 2
                throw new \Exception(sprintf('Path %s not found', $path->getFullPath()));
672
            }
673 6
            if (!is_file($path->getFullPath())) {
674 2
                throw new \Exception(sprintf('Path %s is not a file', $path->getFullPath()));
675
            }
676
677 4
            $repo   = $path->getRepository();
678
679 4
            $commitMsg      = $this->getContextOption('commitMsg', null);
680 4
            $author         = $this->getContextOption('author', null);
681
682 4
            $repo->removeFile($path->getLocalPath(), $commitMsg, false, false, $author);
683 4
            return true;
684 6
        } catch (\Exception $e) {
685 6
            trigger_error($e->getMessage(), E_USER_WARNING);
686
            return false;
687
        }
688
    }
689
690
    /**
691
     * streamWrapper::url_stat — Retrieve information about a file
692
     *
693
     * mode bit mask:
694
     * S_IFMT     0170000   bit mask for the file type bit fields
695
     * S_IFSOCK   0140000   socket
696
     * S_IFLNK    0120000   symbolic link
697
     * S_IFREG    0100000   regular file
698
     * S_IFBLK    0060000   block device
699
     * S_IFDIR    0040000   directory
700
     * S_IFCHR    0020000   character device
701
     * S_IFIFO    0010000   FIFO
702
     * S_ISUID    0004000   set UID bit
703
     * S_ISGID    0002000   set-group-ID bit (see below)
704
     * S_ISVTX    0001000   sticky bit (see below)
705
     * S_IRWXU    00700     mask for file owner permissions
706
     * S_IRUSR    00400     owner has read permission
707
     * S_IWUSR    00200     owner has write permission
708
     * S_IXUSR    00100     owner has execute permission
709
     * S_IRWXG    00070     mask for group permissions
710
     * S_IRGRP    00040     group has read permission
711
     * S_IWGRP    00020     group has write permission
712
     * S_IXGRP    00010     group has execute permission
713
     * S_IRWXO    00007     mask for permissions for others (not in group)
714
     * S_IROTH    00004     others have read permission
715
     * S_IWOTH    00002     others have write permission
716
     * S_IXOTH    00001     others have execute permission
717
     *
718
     * @param   string  $path   The file path or URL to stat. Note that in the case of a URL, it must be a :// delimited URL.
719
     *                          Other URL forms are not supported.
720
     * @param   integer $flags  Holds additional flags set by the streams API. It can hold one or more of the following
721
     *                          values OR'd together.
722
     *                              STREAM_URL_STAT_LINK    For resources with the ability to link to other resource (such
723
     *                                                      as an HTTP Location: forward, or a filesystem symlink). This flag
724
     *                                                      specified that only information about the link itself should be returned,
725
     *                                                      not the resource pointed to by the link. This flag is set in response
726
     *                                                      to calls to lstat(), is_link(), or filetype().
727
     *                              STREAM_URL_STAT_QUIET   If this flag is set, your wrapper should not raise any errors. If this
728
     *                                                      flag is not set, you are responsible for reporting errors using the
729
     *                                                      trigger_error() function during stating of the path.
730
     * @return  array           Should return as many elements as stat() does. Unknown or unavailable values should be set to a
731
     *                          rational value (usually 0).
732
     */
733 12
    public function url_stat($path, $flags)
0 ignored issues
show
Coding Style introduced by
Method name "AbstractStreamWrapper::url_stat" is not in camel caps format
Loading history...
734
    {
735
        try {
736 12
            $path   = $this->getPath($path);
737 12
            if ($path->getRef() == 'HEAD' && file_exists($path->getFullPath())) {
738 8
                return stat($path->getFullPath());
739
            } else {
740 6
                $repo   = $path->getRepository();
741 6
                $info   = $repo->getObjectInfo($path->getLocalPath(), $path->getRef());
742
743
                $stat   = array(
744 6
                    'ino'       => 0,
745 6
                    'mode'      => $info['mode'],
746 6
                    'nlink'     => 0,
747 6
                    'uid'       => 0,
748 6
                    'gid'       => 0,
749 6
                    'rdev'      => 0,
750 6
                    'size'      => $info['size'],
751 6
                    'atime'     => 0,
752 6
                    'mtime'     => 0,
753 6
                    'ctime'     => 0,
754
                    'blksize'   => -1,
755
                    'blocks'    => -1,
756
                );
757 6
                return array_merge($stat, array_values($stat));
758
            }
759
        } catch (\Exception $e) {
760
            if (!self::maskHasFlag($flags, STREAM_URL_STAT_QUIET)) {
761
                trigger_error($e->getMessage(), E_USER_WARNING);
762
            }
763
            return false;
764
        }
765
    }
766
767
    /**
768
     * Checks if a bitmask has a specific flag set
769
     *
770
     * @param   integer     $mask   The bitmask
771
     * @param   integer     $flag   The flag to check
772
     * @return  boolean
773
     */
774 64
    protected static function maskHasFlag($mask, $flag)
775
    {
776 64
        $flag   = (int)$flag;
777 64
        return ((int)$mask & $flag) === $flag;
778
    }
779
}
780