Chris@17: internalResource)) { Chris@17: return false; Chris@17: } Chris@17: Chris@17: $this->invokeInternalStreamWrapper( Chris@17: 'closedir', Chris@17: $this->internalResource Chris@17: ); Chris@17: return !is_resource($this->internalResource); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param string $path Chris@17: * @param int $options Chris@17: * @return bool Chris@17: */ Chris@17: public function dir_opendir($path, $options) Chris@17: { Chris@17: $this->assert($path, Behavior::COMMAND_DIR_OPENDIR); Chris@17: $this->internalResource = $this->invokeInternalStreamWrapper( Chris@17: 'opendir', Chris@17: $path, Chris@17: $this->context Chris@17: ); Chris@17: return is_resource($this->internalResource); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @return string|false Chris@17: */ Chris@17: public function dir_readdir() Chris@17: { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'readdir', Chris@17: $this->internalResource Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @return bool Chris@17: */ Chris@17: public function dir_rewinddir() Chris@17: { Chris@17: if (!is_resource($this->internalResource)) { Chris@17: return false; Chris@17: } Chris@17: Chris@17: $this->invokeInternalStreamWrapper( Chris@17: 'rewinddir', Chris@17: $this->internalResource Chris@17: ); Chris@17: return is_resource($this->internalResource); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param string $path Chris@17: * @param int $mode Chris@17: * @param int $options Chris@17: * @return bool Chris@17: */ Chris@17: public function mkdir($path, $mode, $options) Chris@17: { Chris@17: $this->assert($path, Behavior::COMMAND_MKDIR); Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'mkdir', Chris@17: $path, Chris@17: $mode, Chris@17: (bool) ($options & STREAM_MKDIR_RECURSIVE), Chris@17: $this->context Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param string $path_from Chris@17: * @param string $path_to Chris@17: * @return bool Chris@17: */ Chris@17: public function rename($path_from, $path_to) Chris@17: { Chris@17: $this->assert($path_from, Behavior::COMMAND_RENAME); Chris@17: $this->assert($path_to, Behavior::COMMAND_RENAME); Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'rename', Chris@17: $path_from, Chris@17: $path_to, Chris@17: $this->context Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param string $path Chris@17: * @param int $options Chris@17: * @return bool Chris@17: */ Chris@17: public function rmdir($path, $options) Chris@17: { Chris@17: $this->assert($path, Behavior::COMMAND_RMDIR); Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'rmdir', Chris@17: $path, Chris@17: $this->context Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param int $cast_as Chris@17: */ Chris@17: public function stream_cast($cast_as) Chris@17: { Chris@17: throw new Exception( Chris@17: 'Method stream_select() cannot be used', Chris@17: 1530103999 Chris@17: ); Chris@17: } Chris@17: Chris@17: public function stream_close() Chris@17: { Chris@17: $this->invokeInternalStreamWrapper( Chris@17: 'fclose', Chris@17: $this->internalResource Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @return bool Chris@17: */ Chris@17: public function stream_eof() Chris@17: { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'feof', Chris@17: $this->internalResource Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @return bool Chris@17: */ Chris@17: public function stream_flush() Chris@17: { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'fflush', Chris@17: $this->internalResource Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param int $operation Chris@17: * @return bool Chris@17: */ Chris@17: public function stream_lock($operation) Chris@17: { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'flock', Chris@17: $this->internalResource, Chris@17: $operation Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param string $path Chris@17: * @param int $option Chris@17: * @param string|int $value Chris@17: * @return bool Chris@17: */ Chris@17: public function stream_metadata($path, $option, $value) Chris@17: { Chris@17: $this->assert($path, Behavior::COMMAND_STEAM_METADATA); Chris@17: if ($option === STREAM_META_TOUCH) { Chris@17: return call_user_func_array( Chris@17: array($this, 'invokeInternalStreamWrapper'), Chris@17: array_merge(array('touch', $path), (array) $value) Chris@17: ); Chris@17: } Chris@17: if ($option === STREAM_META_OWNER_NAME || $option === STREAM_META_OWNER) { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'chown', Chris@17: $path, Chris@17: $value Chris@17: ); Chris@17: } Chris@17: if ($option === STREAM_META_GROUP_NAME || $option === STREAM_META_GROUP) { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'chgrp', Chris@17: $path, Chris@17: $value Chris@17: ); Chris@17: } Chris@17: if ($option === STREAM_META_ACCESS) { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'chmod', Chris@17: $path, Chris@17: $value Chris@17: ); Chris@17: } Chris@17: return false; Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param string $path Chris@17: * @param string $mode Chris@17: * @param int $options Chris@17: * @param string|null $opened_path Chris@17: * @return bool Chris@17: */ Chris@17: public function stream_open( Chris@17: $path, Chris@17: $mode, Chris@17: $options, Chris@17: &$opened_path = null Chris@17: ) { Chris@17: $this->assert($path, Behavior::COMMAND_STREAM_OPEN); Chris@17: $arguments = array($path, $mode, (bool) ($options & STREAM_USE_PATH)); Chris@17: // only add stream context for non include/require calls Chris@17: if (!($options & static::STREAM_OPEN_FOR_INCLUDE)) { Chris@17: $arguments[] = $this->context; Chris@17: // work around https://bugs.php.net/bug.php?id=66569 Chris@17: // for including files from Phar stream with OPcache enabled Chris@17: } else { Chris@17: Helper::resetOpCache(); Chris@17: } Chris@17: $this->internalResource = call_user_func_array( Chris@17: array($this, 'invokeInternalStreamWrapper'), Chris@17: array_merge(array('fopen'), $arguments) Chris@17: ); Chris@17: if (!is_resource($this->internalResource)) { Chris@17: return false; Chris@17: } Chris@17: if ($opened_path !== null) { Chris@17: $metaData = stream_get_meta_data($this->internalResource); Chris@17: $opened_path = $metaData['uri']; Chris@17: } Chris@17: return true; Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param int $count Chris@17: * @return string Chris@17: */ Chris@17: public function stream_read($count) Chris@17: { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'fread', Chris@17: $this->internalResource, Chris@17: $count Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param int $offset Chris@17: * @param int $whence Chris@17: * @return bool Chris@17: */ Chris@17: public function stream_seek($offset, $whence = SEEK_SET) Chris@17: { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'fseek', Chris@17: $this->internalResource, Chris@17: $offset, Chris@17: $whence Chris@17: ) !== -1; Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param int $option Chris@17: * @param int $arg1 Chris@17: * @param int $arg2 Chris@17: * @return bool Chris@17: */ Chris@17: public function stream_set_option($option, $arg1, $arg2) Chris@17: { Chris@17: if ($option === STREAM_OPTION_BLOCKING) { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'stream_set_blocking', Chris@17: $this->internalResource, Chris@17: $arg1 Chris@17: ); Chris@17: } Chris@17: if ($option === STREAM_OPTION_READ_TIMEOUT) { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'stream_set_timeout', Chris@17: $this->internalResource, Chris@17: $arg1, Chris@17: $arg2 Chris@17: ); Chris@17: } Chris@17: if ($option === STREAM_OPTION_WRITE_BUFFER) { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'stream_set_write_buffer', Chris@17: $this->internalResource, Chris@17: $arg2 Chris@17: ) === 0; Chris@17: } Chris@17: return false; Chris@17: } Chris@17: Chris@17: /** Chris@17: * @return array Chris@17: */ Chris@17: public function stream_stat() Chris@17: { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'fstat', Chris@17: $this->internalResource Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @return int Chris@17: */ Chris@17: public function stream_tell() Chris@17: { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'ftell', Chris@17: $this->internalResource Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param int $new_size Chris@17: * @return bool Chris@17: */ Chris@17: public function stream_truncate($new_size) Chris@17: { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'ftruncate', Chris@17: $this->internalResource, Chris@17: $new_size Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param string $data Chris@17: * @return int Chris@17: */ Chris@17: public function stream_write($data) Chris@17: { Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'fwrite', Chris@17: $this->internalResource, Chris@17: $data Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param string $path Chris@17: * @return bool Chris@17: */ Chris@17: public function unlink($path) Chris@17: { Chris@17: $this->assert($path, Behavior::COMMAND_UNLINK); Chris@17: return $this->invokeInternalStreamWrapper( Chris@17: 'unlink', Chris@17: $path, Chris@17: $this->context Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param string $path Chris@17: * @param int $flags Chris@17: * @return array|false Chris@17: */ Chris@17: public function url_stat($path, $flags) Chris@17: { Chris@17: $this->assert($path, Behavior::COMMAND_URL_STAT); Chris@17: $functionName = $flags & STREAM_URL_STAT_QUIET ? '@stat' : 'stat'; Chris@17: return $this->invokeInternalStreamWrapper($functionName, $path); Chris@17: } Chris@17: Chris@17: /** Chris@17: * @param string $path Chris@17: * @param string $command Chris@17: */ Chris@17: protected function assert($path, $command) Chris@17: { Chris@18: if (Manager::instance()->assert($path, $command) === true) { Chris@18: $this->collectInvocation($path); Chris@17: return; Chris@17: } Chris@17: Chris@17: throw new Exception( Chris@17: sprintf( Chris@17: 'Denied invocation of "%s" for command "%s"', Chris@17: $path, Chris@17: $command Chris@17: ), Chris@17: 1535189880 Chris@17: ); Chris@17: } Chris@17: Chris@17: /** Chris@18: * @param string $path Chris@18: */ Chris@18: protected function collectInvocation($path) Chris@18: { Chris@18: if (isset($this->invocation)) { Chris@18: return; Chris@18: } Chris@18: Chris@18: $manager = Manager::instance(); Chris@18: $this->invocation = $manager->resolve($path); Chris@18: if ($this->invocation === null) { Chris@18: throw new Exception( Chris@18: 'Expected invocation could not be resolved', Chris@18: 1556389591 Chris@18: ); Chris@18: } Chris@18: // confirm, previous interceptor(s) validated invocation Chris@18: $this->invocation->confirm(); Chris@18: $collection = $manager->getCollection(); Chris@18: if (!$collection->has($this->invocation)) { Chris@18: $collection->collect($this->invocation); Chris@18: } Chris@18: } Chris@18: Chris@18: /** Chris@18: * @return Manager|Assertable Chris@18: * @deprecated Use Manager::instance() directly Chris@17: */ Chris@17: protected function resolveAssertable() Chris@17: { Chris@17: return Manager::instance(); Chris@17: } Chris@17: Chris@17: /** Chris@17: * Invokes commands on the native PHP Phar stream wrapper. Chris@17: * Chris@17: * @param string $functionName Chris@17: * @param mixed ...$arguments Chris@17: * @return mixed Chris@17: */ Chris@17: private function invokeInternalStreamWrapper($functionName) Chris@17: { Chris@17: $arguments = func_get_args(); Chris@17: array_shift($arguments); Chris@17: $silentExecution = $functionName{0} === '@'; Chris@17: $functionName = ltrim($functionName, '@'); Chris@17: $this->restoreInternalSteamWrapper(); Chris@17: Chris@17: try { Chris@17: if ($silentExecution) { Chris@17: $result = @call_user_func_array($functionName, $arguments); Chris@17: } else { Chris@17: $result = call_user_func_array($functionName, $arguments); Chris@17: } Chris@17: } catch (\Exception $exception) { Chris@17: $this->registerStreamWrapper(); Chris@17: throw $exception; Chris@17: } catch (\Throwable $throwable) { Chris@17: $this->registerStreamWrapper(); Chris@17: throw $throwable; Chris@17: } Chris@17: Chris@17: $this->registerStreamWrapper(); Chris@17: return $result; Chris@17: } Chris@17: Chris@17: private function restoreInternalSteamWrapper() Chris@17: { Chris@17: stream_wrapper_restore('phar'); Chris@17: } Chris@17: Chris@17: private function registerStreamWrapper() Chris@17: { Chris@17: stream_wrapper_unregister('phar'); Chris@17: stream_wrapper_register('phar', get_class($this)); Chris@17: } Chris@17: }