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