Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/*** Hoa*** @license** New BSD License** Copyright © 2007-2017, Hoa community. All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions are met:* * Redistributions of source code must retain the above copyright* notice, this list of conditions and the following disclaimer.* * Redistributions in binary form must reproduce the above copyright* notice, this list of conditions and the following disclaimer in the* documentation and/or other materials provided with the distribution.* * Neither the name of the Hoa nor the names of its contributors may be* used to endorse or promote products derived from this software without* specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE* POSSIBILITY OF SUCH DAMAGE.*/namespace Psy\Readline\Hoa;/*** Stream wrapper for the `hoa://` protocol.*/class ProtocolWrapper{/*** Opened stream as a resource.*/private $_stream = null;/*** Stream name (filename).*/private $_streamName = null;/*** Stream context (given by the streamWrapper class) as a resource.*/public $context = null;/*** Get the real path of the given URL.* Could return false if the path cannot be reached.*/public static function realPath(string $path, bool $exists = true){return ProtocolNode::getRoot()->resolve($path, $exists);}/*** Retrieve the underlying resource.** `$castAs` can be `STREAM_CAST_FOR_SELECT` when `stream_select` is* calling `stream_cast` or `STREAM_CAST_AS_STREAM` when `stream_cast` is* called for other uses.*/public function stream_cast(int $castAs){return null;}/*** Closes a resource.* This method is called in response to `fclose`.* All resources that were locked, or allocated, by the wrapper should be* released.*/public function stream_close(){if (true === @\fclose($this->getStream())) {$this->_stream = null;$this->_streamName = null;}}/*** Tests for end-of-file on a file pointer.* This method is called in response to feof().*/public function stream_eof(): bool{return \feof($this->getStream());}/*** Flush the output.* This method is called in respond to fflush().* If we have cached data in our stream but not yet stored it into the* underlying storage, we should do so now.*/public function stream_flush(): bool{return \fflush($this->getStream());}/*** Advisory file locking.* This method is called in response to flock(), when file_put_contents()* (when flags contains LOCK_EX), stream_set_blocking() and when closing the* stream (LOCK_UN).** Operation is one the following:* * LOCK_SH to acquire a shared lock (reader) ;* * LOCK_EX to acquire an exclusive lock (writer) ;* * LOCK_UN to release a lock (shared or exclusive) ;* * LOCK_NB if we don't want flock() to* block while locking (not supported on* Windows).*/public function stream_lock(int $operation): bool{return \flock($this->getStream(), $operation);}/*** Change stream options.* This method is called to set metadata on the stream. It is called when* one of the following functions is called on a stream URL: touch, chmod,* chown or chgrp.** Option must be one of the following constant:* * STREAM_META_TOUCH,* * STREAM_META_OWNER_NAME,* * STREAM_META_OWNER,* * STREAM_META_GROUP_NAME,* * STREAM_META_GROUP,* * STREAM_META_ACCESS.** Values are arguments of `touch`, `chmod`, `chown`, and `chgrp`.*/public function stream_metadata(string $path, int $option, $values): bool{$path = static::realPath($path, false);switch ($option) {case \STREAM_META_TOUCH:$arity = \count($values);if (0 === $arity) {$out = \touch($path);} elseif (1 === $arity) {$out = \touch($path, $values[0]);} else {$out = \touch($path, $values[0], $values[1]);}break;case \STREAM_META_OWNER_NAME:case \STREAM_META_OWNER:$out = \chown($path, $values);break;case \STREAM_META_GROUP_NAME:case \STREAM_META_GROUP:$out = \chgrp($path, $values);break;case \STREAM_META_ACCESS:$out = \chmod($path, $values);break;default:$out = false;}return $out;}/*** Open file or URL.* This method is called immediately after the wrapper is initialized (f.e.* by fopen() and file_get_contents()).*/public function stream_open(string $path, string $mode, int $options, &$openedPath): bool{$path = static::realPath($path, 'r' === $mode[0]);if (Protocol::NO_RESOLUTION === $path) {return false;}if (null === $this->context) {$openedPath = \fopen($path, $mode, $options & \STREAM_USE_PATH);} else {$openedPath = \fopen($path,$mode,(bool) ($options & \STREAM_USE_PATH),$this->context);}if (false === \is_resource($openedPath)) {return false;}$this->_stream = $openedPath;$this->_streamName = $path;return true;}/*** Read from stream.* This method is called in response to fread() and fgets().*/public function stream_read(int $size): string{return \fread($this->getStream(), $size);}/*** Seek to specific location in a stream.* This method is called in response to fseek().* The read/write position of the stream should be updated according to the* $offset and $whence.** The possible values for `$whence` are:* * SEEK_SET to set position equal to $offset bytes,* * SEEK_CUR to set position to current location plus `$offset`,* * SEEK_END to set position to end-of-file plus `$offset`.*/public function stream_seek(int $offset, int $whence = \SEEK_SET): bool{return 0 === \fseek($this->getStream(), $offset, $whence);}/*** Retrieve information about a file resource.* This method is called in response to fstat().*/public function stream_stat(): array{return \fstat($this->getStream());}/*** Retrieve the current position of a stream.* This method is called in response to ftell().*/public function stream_tell(): int{return \ftell($this->getStream());}/*** Truncate a stream to a given length.*/public function stream_truncate(int $size): bool{return \ftruncate($this->getStream(), $size);}/*** Write to stream.* This method is called in response to fwrite().*/public function stream_write(string $data): int{return \fwrite($this->getStream(), $data);}/*** Close directory handle.* This method is called in to closedir().* Any resources which were locked, or allocated, during opening and use of* the directory stream should be released.*/public function dir_closedir(){\closedir($this->getStream());$this->_stream = null;$this->_streamName = null;}/*** Open directory handle.* This method is called in response to opendir().** The `$options` input represents whether or not to enforce safe_mode* (0x04). It is not used here.*/public function dir_opendir(string $path, int $options): bool{$path = static::realPath($path);$handle = null;if (null === $this->context) {$handle = @\opendir($path);} else {$handle = @\opendir($path, $this->context);}if (false === $handle) {return false;}$this->_stream = $handle;$this->_streamName = $path;return true;}/*** Read entry from directory handle.* This method is called in response to readdir().** @return mixed*/public function dir_readdir(){return \readdir($this->getStream());}/*** Rewind directory handle.* This method is called in response to rewinddir().* Should reset the output generated by self::dir_readdir, i.e. the next* call to self::dir_readdir should return the first entry in the location* returned by self::dir_opendir.*/public function dir_rewinddir(){\rewinddir($this->getStream());}/*** Create a directory.* This method is called in response to mkdir().*/public function mkdir(string $path, int $mode, int $options): bool{if (null === $this->context) {return \mkdir(static::realPath($path, false),$mode,$options | \STREAM_MKDIR_RECURSIVE);}return \mkdir(static::realPath($path, false),$mode,(bool) ($options | \STREAM_MKDIR_RECURSIVE),$this->context);}/*** Rename a file or directory.* This method is called in response to rename().* Should attempt to rename $from to $to.*/public function rename(string $from, string $to): bool{if (null === $this->context) {return \rename(static::realPath($from), static::realPath($to, false));}return \rename(static::realPath($from),static::realPath($to, false),$this->context);}/*** Remove a directory.* This method is called in response to rmdir().* The `$options` input is a bitwise mask of values. It is not used here.*/public function rmdir(string $path, int $options): bool{if (null === $this->context) {return \rmdir(static::realPath($path));}return \rmdir(static::realPath($path), $this->context);}/*** Delete a file.* This method is called in response to unlink().*/public function unlink(string $path): bool{if (null === $this->context) {return \unlink(static::realPath($path));}return \unlink(static::realPath($path), $this->context);}/*** Retrieve information about a file.* This method is called in response to all stat() related functions.* The `$flags` input holds additional flags set by the streams API. It* can hold one or more of the following values OR'd together.* STREAM_URL_STAT_LINK: for resource with the ability to link to other* resource (such as an HTTP location: forward, or a filesystem* symlink). This flag specified that only information about the link* itself should be returned, not the resource pointed to by the* link. This flag is set in response to calls to lstat(), is_link(), or* filetype(). STREAM_URL_STAT_QUIET: if this flag is set, our wrapper* should not raise any errors. If this flag is not set, we are* responsible for reporting errors using the trigger_error() function* during stating of the path.*/public function url_stat(string $path, int $flags){$path = static::realPath($path);if (Protocol::NO_RESOLUTION === $path) {if ($flags & \STREAM_URL_STAT_QUIET) {return 0;} else {return \trigger_error('Path '.$path.' cannot be resolved.',\E_WARNING);}}if ($flags & \STREAM_URL_STAT_LINK) {return @\lstat($path);}return @\stat($path);}/*** Get stream resource.*/public function getStream(){return $this->_stream;}/*** Get stream name.*/public function getStreamName(){return $this->_streamName;}}/** Register the `hoa://` protocol.*/\stream_wrapper_register('hoa', ProtocolWrapper::class);