You are here

vfsStreamWrapper.php in Zircon Profile 8

Namespace

org\bovigo\vfs

File

vendor/mikey179/vfsStream/src/main/php/org/bovigo/vfs/vfsStreamWrapper.php
View source
<?php

/**
 * This file is part of vfsStream.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @package  org\bovigo\vfs
 */
namespace org\bovigo\vfs;


/**
 * Stream wrapper to mock file system requests.
 */
class vfsStreamWrapper {

  /**
   * open file for reading
   */
  const READ = 'r';

  /**
   * truncate file
   */
  const TRUNCATE = 'w';

  /**
   * set file pointer to end, append new data
   */
  const APPEND = 'a';

  /**
   * set file pointer to start, overwrite existing data
   */
  const WRITE = 'x';

  /**
   * set file pointer to start, overwrite existing data; or create file if
   * does not exist
   */
  const WRITE_NEW = 'c';

  /**
   * file mode: read only
   */
  const READONLY = 0;

  /**
   * file mode: write only
   */
  const WRITEONLY = 1;

  /**
   * file mode: read and write
   */
  const ALL = 2;

  /**
   * switch whether class has already been registered as stream wrapper or not
   *
   * @type  bool
   */
  protected static $registered = false;

  /**
   * root content
   *
   * @type  vfsStreamContent
   */
  protected static $root;

  /**
   * disk space quota
   *
   * @type  Quota
   */
  private static $quota;

  /**
   * file mode: read only, write only, all
   *
   * @type  int
   */
  protected $mode;

  /**
   * shortcut to file container
   *
   * @type  vfsStreamFile
   */
  protected $content;

  /**
   * shortcut to directory container
   *
   * @type  vfsStreamDirectory
   */
  protected $dir;

  /**
   * shortcut to directory container iterator
   *
   * @type  vfsStreamDirectory
   */
  protected $dirIterator;

  /**
   * method to register the stream wrapper
   *
   * Please be aware that a call to this method will reset the root element
   * to null.
   * If the stream is already registered the method returns silently. If there
   * is already another stream wrapper registered for the scheme used by
   * vfsStream a vfsStreamException will be thrown.
   *
   * @throws  vfsStreamException
   */
  public static function register() {
    self::$root = null;
    self::$quota = Quota::unlimited();
    if (true === self::$registered) {
      return;
    }
    if (@stream_wrapper_register(vfsStream::SCHEME, __CLASS__) === false) {
      throw new vfsStreamException('A handler has already been registered for the ' . vfsStream::SCHEME . ' protocol.');
    }
    self::$registered = true;
  }

  /**
   * Unregisters a previously registered URL wrapper for the vfs scheme.
   *
   * If this stream wrapper wasn't registered, the method returns silently.
   *
   * If unregistering fails, or if the URL wrapper for vfs:// was not
   * registered with this class, a vfsStreamException will be thrown.
   *
   * @throws vfsStreamException
   * @since  1.6.0
   */
  public static function unregister() {
    if (!self::$registered) {
      if (in_array(vfsStream::SCHEME, stream_get_wrappers())) {
        throw new vfsStreamException('The URL wrapper for the protocol ' . vfsStream::SCHEME . ' was not registered with this version of vfsStream.');
      }
      return;
    }
    if (!@stream_wrapper_unregister(vfsStream::SCHEME)) {
      throw new vfsStreamException('Failed to unregister the URL wrapper for the ' . vfsStream::SCHEME . ' protocol.');
    }
    self::$registered = false;
  }

  /**
   * sets the root content
   *
   * @param   vfsStreamContainer  $root
   * @return  vfsStreamContainer
   */
  public static function setRoot(vfsStreamContainer $root) {
    self::$root = $root;
    clearstatcache();
    return self::$root;
  }

  /**
   * returns the root content
   *
   * @return  vfsStreamContainer
   */
  public static function getRoot() {
    return self::$root;
  }

  /**
   * sets quota for disk space
   *
   * @param  Quota  $quota
   * @since  1.1.0
   */
  public static function setQuota(Quota $quota) {
    self::$quota = $quota;
  }

  /**
   * returns content for given path
   *
   * @param   string  $path
   * @return  vfsStreamContent
   */
  protected function getContent($path) {
    if (null === self::$root) {
      return null;
    }
    if (self::$root
      ->getName() === $path) {
      return self::$root;
    }
    if ($this
      ->isInRoot($path) && self::$root
      ->hasChild($path) === true) {
      return self::$root
        ->getChild($path);
    }
    return null;
  }

  /**
   * helper method to detect whether given path is in root path
   *
   * @param   string  $path
   * @return  bool
   */
  private function isInRoot($path) {
    return substr($path, 0, strlen(self::$root
      ->getName())) === self::$root
      ->getName();
  }

  /**
   * returns content for given path but only when it is of given type
   *
   * @param   string  $path
   * @param   int     $type
   * @return  vfsStreamContent
   */
  protected function getContentOfType($path, $type) {
    $content = $this
      ->getContent($path);
    if (null !== $content && $content
      ->getType() === $type) {
      return $content;
    }
    return null;
  }

  /**
   * splits path into its dirname and the basename
   *
   * @param   string  $path
   * @return  string[]
   */
  protected function splitPath($path) {
    $lastSlashPos = strrpos($path, '/');
    if (false === $lastSlashPos) {
      return array(
        'dirname' => '',
        'basename' => $path,
      );
    }
    return array(
      'dirname' => substr($path, 0, $lastSlashPos),
      'basename' => substr($path, $lastSlashPos + 1),
    );
  }

  /**
   * helper method to resolve a path from /foo/bar/. to /foo/bar
   *
   * @param   string  $path
   * @return  string
   */
  protected function resolvePath($path) {
    $newPath = array();
    foreach (explode('/', $path) as $pathPart) {
      if ('.' !== $pathPart) {
        if ('..' !== $pathPart) {
          $newPath[] = $pathPart;
        }
        elseif (count($newPath) > 1) {
          array_pop($newPath);
        }
      }
    }
    return implode('/', $newPath);
  }

  /**
   * open the stream
   *
   * @param   string  $path         the path to open
   * @param   string  $mode         mode for opening
   * @param   string  $options      options for opening
   * @param   string  $opened_path  full path that was actually opened
   * @return  bool
   */
  public function stream_open($path, $mode, $options, $opened_path) {
    $extended = strstr($mode, '+') !== false ? true : false;
    $mode = str_replace(array(
      't',
      'b',
      '+',
    ), '', $mode);
    if (in_array($mode, array(
      'r',
      'w',
      'a',
      'x',
      'c',
    )) === false) {
      if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) {
        trigger_error('Illegal mode ' . $mode . ', use r, w, a, x  or c, flavoured with t, b and/or +', E_USER_WARNING);
      }
      return false;
    }
    $this->mode = $this
      ->calculateMode($mode, $extended);
    $path = $this
      ->resolvePath(vfsStream::path($path));
    $this->content = $this
      ->getContentOfType($path, vfsStreamContent::TYPE_FILE);
    if (null !== $this->content) {
      if (self::WRITE === $mode) {
        if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) {
          trigger_error('File ' . $path . ' already exists, can not open with mode x', E_USER_WARNING);
        }
        return false;
      }
      if ((self::TRUNCATE === $mode || self::APPEND === $mode) && $this->content
        ->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {
        return false;
      }
      if (self::TRUNCATE === $mode) {
        $this->content
          ->openWithTruncate();
      }
      elseif (self::APPEND === $mode) {
        $this->content
          ->openForAppend();
      }
      else {
        if (!$this->content
          ->isReadable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup())) {
          if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) {
            trigger_error('Permission denied', E_USER_WARNING);
          }
          return false;
        }
        $this->content
          ->open();
      }
      return true;
    }
    $content = $this
      ->createFile($path, $mode, $options);
    if (false === $content) {
      return false;
    }
    $this->content = $content;
    return true;
  }

  /**
   * creates a file at given path
   *
   * @param   string  $path     the path to open
   * @param   string  $mode     mode for opening
   * @param   string  $options  options for opening
   * @return  bool
   */
  private function createFile($path, $mode = null, $options = null) {
    $names = $this
      ->splitPath($path);
    if (empty($names['dirname']) === true) {
      if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) {
        trigger_error('File ' . $names['basename'] . ' does not exist', E_USER_WARNING);
      }
      return false;
    }
    $dir = $this
      ->getContentOfType($names['dirname'], vfsStreamContent::TYPE_DIR);
    if (null === $dir) {
      if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) {
        trigger_error('Directory ' . $names['dirname'] . ' does not exist', E_USER_WARNING);
      }
      return false;
    }
    elseif ($dir
      ->hasChild($names['basename']) === true) {
      if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) {
        trigger_error('Directory ' . $names['dirname'] . ' already contains a director named ' . $names['basename'], E_USER_WARNING);
      }
      return false;
    }
    if (self::READ === $mode) {
      if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) {
        trigger_error('Can not open non-existing file ' . $path . ' for reading', E_USER_WARNING);
      }
      return false;
    }
    if ($dir
      ->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {
      if (($options & STREAM_REPORT_ERRORS) === STREAM_REPORT_ERRORS) {
        trigger_error('Can not create new file in non-writable path ' . $names['dirname'], E_USER_WARNING);
      }
      return false;
    }
    return vfsStream::newFile($names['basename'])
      ->at($dir);
  }

  /**
   * calculates the file mode
   *
   * @param   string  $mode      opening mode: r, w, a or x
   * @param   bool    $extended  true if + was set with opening mode
   * @return  int
   */
  protected function calculateMode($mode, $extended) {
    if (true === $extended) {
      return self::ALL;
    }
    if (self::READ === $mode) {
      return self::READONLY;
    }
    return self::WRITEONLY;
  }

  /**
   * closes the stream
   *
   * @see     https://github.com/mikey179/vfsStream/issues/40
   */
  public function stream_close() {
    $this->content
      ->lock($this, LOCK_UN);
  }

  /**
   * read the stream up to $count bytes
   *
   * @param   int     $count  amount of bytes to read
   * @return  string
   */
  public function stream_read($count) {
    if (self::WRITEONLY === $this->mode) {
      return '';
    }
    if ($this->content
      ->isReadable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {
      return '';
    }
    return $this->content
      ->read($count);
  }

  /**
   * writes data into the stream
   *
   * @param   string  $data
   * @return  int     amount of bytes written
   */
  public function stream_write($data) {
    if (self::READONLY === $this->mode) {
      return 0;
    }
    if ($this->content
      ->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {
      return 0;
    }
    if (self::$quota
      ->isLimited()) {
      $data = substr($data, 0, self::$quota
        ->spaceLeft(self::$root
        ->sizeSummarized()));
    }
    return $this->content
      ->write($data);
  }

  /**
   * truncates a file to a given length
   *
   * @param   int  $size  length to truncate file to
   * @return  bool
   * @since   1.1.0
   */
  public function stream_truncate($size) {
    if (self::READONLY === $this->mode) {
      return false;
    }
    if ($this->content
      ->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {
      return false;
    }
    if ($this->content
      ->getType() !== vfsStreamContent::TYPE_FILE) {
      return false;
    }
    if (self::$quota
      ->isLimited() && $this->content
      ->size() < $size) {
      $maxSize = self::$quota
        ->spaceLeft(self::$root
        ->sizeSummarized());
      if (0 === $maxSize) {
        return false;
      }
      if ($size > $maxSize) {
        $size = $maxSize;
      }
    }
    return $this->content
      ->truncate($size);
  }

  /**
   * sets metadata like owner, user or permissions
   *
   * @param   string  $path
   * @param   int     $option
   * @param   mixed   $var
   * @return  bool
   * @since   1.1.0
   */
  public function stream_metadata($path, $option, $var) {
    $path = $this
      ->resolvePath(vfsStream::path($path));
    $content = $this
      ->getContent($path);
    switch ($option) {
      case STREAM_META_TOUCH:
        if (null === $content) {
          $content = $this
            ->createFile($path, null, STREAM_REPORT_ERRORS);

          // file creation may not be allowed at provided path
          if (false === $content) {
            return false;
          }
        }
        $currentTime = time();
        $content
          ->lastModified(isset($var[0]) ? $var[0] : $currentTime)
          ->lastAccessed(isset($var[1]) ? $var[1] : $currentTime);
        return true;
      case STREAM_META_OWNER_NAME:
        return false;
      case STREAM_META_OWNER:
        if (null === $content) {
          return false;
        }
        return $this
          ->doPermChange($path, $content, function () use ($content, $var) {
          $content
            ->chown($var);
        });
      case STREAM_META_GROUP_NAME:
        return false;
      case STREAM_META_GROUP:
        if (null === $content) {
          return false;
        }
        return $this
          ->doPermChange($path, $content, function () use ($content, $var) {
          $content
            ->chgrp($var);
        });
      case STREAM_META_ACCESS:
        if (null === $content) {
          return false;
        }
        return $this
          ->doPermChange($path, $content, function () use ($content, $var) {
          $content
            ->chmod($var);
        });
      default:
        return false;
    }
  }

  /**
   * executes given permission change when necessary rights allow such a change
   *
   * @param   string                    $path
   * @param   vfsStreamAbstractContent  $content
   * @param   \Closure                  $change
   * @return  bool
   */
  private function doPermChange($path, vfsStreamAbstractContent $content, \Closure $change) {
    if (!$content
      ->isOwnedByUser(vfsStream::getCurrentUser())) {
      return false;
    }
    if (self::$root
      ->getName() !== $path) {
      $names = $this
        ->splitPath($path);
      $parent = $this
        ->getContent($names['dirname']);
      if (!$parent
        ->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup())) {
        return false;
      }
    }
    $change();
    return true;
  }

  /**
   * checks whether stream is at end of file
   *
   * @return  bool
   */
  public function stream_eof() {
    return $this->content
      ->eof();
  }

  /**
   * returns the current position of the stream
   *
   * @return  int
   */
  public function stream_tell() {
    return $this->content
      ->getBytesRead();
  }

  /**
   * seeks to the given offset
   *
   * @param   int   $offset
   * @param   int   $whence
   * @return  bool
   */
  public function stream_seek($offset, $whence) {
    return $this->content
      ->seek($offset, $whence);
  }

  /**
   * flushes unstored data into storage
   *
   * @return  bool
   */
  public function stream_flush() {
    return true;
  }

  /**
   * returns status of stream
   *
   * @return  array
   */
  public function stream_stat() {
    $fileStat = array(
      'dev' => 0,
      'ino' => 0,
      'mode' => $this->content
        ->getType() | $this->content
        ->getPermissions(),
      'nlink' => 0,
      'uid' => $this->content
        ->getUser(),
      'gid' => $this->content
        ->getGroup(),
      'rdev' => 0,
      'size' => $this->content
        ->size(),
      'atime' => $this->content
        ->fileatime(),
      'mtime' => $this->content
        ->filemtime(),
      'ctime' => $this->content
        ->filectime(),
      'blksize' => -1,
      'blocks' => -1,
    );
    return array_merge(array_values($fileStat), $fileStat);
  }

  /**
   * retrieve the underlaying resource
   *
   * Please note that this method always returns false as there is no
   * underlaying resource to return.
   *
   * @param   int  $cast_as
   * @since   0.9.0
   * @see     https://github.com/mikey179/vfsStream/issues/3
   * @return  bool
   */
  public function stream_cast($cast_as) {
    return false;
  }

  /**
   * set lock status for stream
   *
   * @param   int   $operation
   * @return  bool
   * @since   0.10.0
   * @see     https://github.com/mikey179/vfsStream/issues/6
   * @see     https://github.com/mikey179/vfsStream/issues/31
   * @see     https://github.com/mikey179/vfsStream/issues/40
   */
  public function stream_lock($operation) {
    if ((LOCK_NB & $operation) == LOCK_NB) {
      $operation = $operation - LOCK_NB;
    }
    return $this->content
      ->lock($this, $operation);
  }

  /**
   * sets options on the stream
   *
   * @param   int   $option  key of option to set
   * @param   int   $arg1
   * @param   int   $arg2
   * @return  bool
   * @since   0.10.0
   * @see     https://github.com/mikey179/vfsStream/issues/15
   * @see     http://www.php.net/manual/streamwrapper.stream-set-option.php
   */
  public function stream_set_option($option, $arg1, $arg2) {
    switch ($option) {
      case STREAM_OPTION_BLOCKING:

      // break omitted
      case STREAM_OPTION_READ_TIMEOUT:

      // break omitted
      case STREAM_OPTION_WRITE_BUFFER:

      // break omitted
      default:
    }
    return false;
  }

  /**
   * remove the data under the given path
   *
   * @param   string  $path
   * @return  bool
   */
  public function unlink($path) {
    $realPath = $this
      ->resolvePath(vfsStream::path($path));
    $content = $this
      ->getContent($realPath);
    if (null === $content) {
      trigger_error('unlink(' . $path . '): No such file or directory', E_USER_WARNING);
      return false;
    }
    if ($content
      ->getType() !== vfsStreamContent::TYPE_FILE) {
      trigger_error('unlink(' . $path . '): Operation not permitted', E_USER_WARNING);
      return false;
    }
    return $this
      ->doUnlink($realPath);
  }

  /**
   * removes a path
   *
   * @param   string  $path
   * @return  bool
   */
  protected function doUnlink($path) {
    if (self::$root
      ->getName() === $path) {

      // delete root? very brave. :)
      self::$root = null;
      clearstatcache();
      return true;
    }
    $names = $this
      ->splitPath($path);
    $content = $this
      ->getContent($names['dirname']);
    if (!$content
      ->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup())) {
      return false;
    }
    clearstatcache();
    return $content
      ->removeChild($names['basename']);
  }

  /**
   * rename from one path to another
   *
   * @param   string  $path_from
   * @param   string  $path_to
   * @return  bool
   * @author  Benoit Aubuchon
   */
  public function rename($path_from, $path_to) {
    $srcRealPath = $this
      ->resolvePath(vfsStream::path($path_from));
    $dstRealPath = $this
      ->resolvePath(vfsStream::path($path_to));
    $srcContent = $this
      ->getContent($srcRealPath);
    if (null == $srcContent) {
      trigger_error(' No such file or directory', E_USER_WARNING);
      return false;
    }
    $dstNames = $this
      ->splitPath($dstRealPath);
    $dstParentContent = $this
      ->getContent($dstNames['dirname']);
    if (null == $dstParentContent) {
      trigger_error('No such file or directory', E_USER_WARNING);
      return false;
    }
    if (!$dstParentContent
      ->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup())) {
      trigger_error('Permission denied', E_USER_WARNING);
      return false;
    }
    if ($dstParentContent
      ->getType() !== vfsStreamContent::TYPE_DIR) {
      trigger_error('Target is not a directory', E_USER_WARNING);
      return false;
    }

    // remove old source first, so we can rename later
    // (renaming first would lead to not being able to remove the old path)
    if (!$this
      ->doUnlink($srcRealPath)) {
      return false;
    }
    $dstContent = $srcContent;

    // Renaming the filename
    $dstContent
      ->rename($dstNames['basename']);

    // Copying to the destination
    $dstParentContent
      ->addChild($dstContent);
    return true;
  }

  /**
   * creates a new directory
   *
   * @param   string  $path
   * @param   int     $mode
   * @param   int     $options
   * @return  bool
   */
  public function mkdir($path, $mode, $options) {
    $umask = vfsStream::umask();
    if (0 < $umask) {
      $permissions = $mode & ~$umask;
    }
    else {
      $permissions = $mode;
    }
    $path = $this
      ->resolvePath(vfsStream::path($path));
    if (null !== $this
      ->getContent($path)) {
      trigger_error('mkdir(): Path vfs://' . $path . ' exists', E_USER_WARNING);
      return false;
    }
    if (null === self::$root) {
      self::$root = vfsStream::newDirectory($path, $permissions);
      return true;
    }
    $maxDepth = count(explode('/', $path));
    $names = $this
      ->splitPath($path);
    $newDirs = $names['basename'];
    $dir = null;
    $i = 0;
    while ($dir === null && $i < $maxDepth) {
      $dir = $this
        ->getContent($names['dirname']);
      $names = $this
        ->splitPath($names['dirname']);
      if (null == $dir) {
        $newDirs = $names['basename'] . '/' . $newDirs;
      }
      $i++;
    }
    if (null === $dir || $dir
      ->getType() !== vfsStreamContent::TYPE_DIR || $dir
      ->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {
      return false;
    }
    $recursive = (STREAM_MKDIR_RECURSIVE & $options) !== 0 ? true : false;
    if (strpos($newDirs, '/') !== false && false === $recursive) {
      return false;
    }
    vfsStream::newDirectory($newDirs, $permissions)
      ->at($dir);
    return true;
  }

  /**
   * removes a directory
   *
   * @param   string  $path
   * @param   int     $options
   * @return  bool
   * @todo    consider $options with STREAM_MKDIR_RECURSIVE
   */
  public function rmdir($path, $options) {
    $path = $this
      ->resolvePath(vfsStream::path($path));
    $child = $this
      ->getContentOfType($path, vfsStreamContent::TYPE_DIR);
    if (null === $child) {
      return false;
    }

    // can only remove empty directories
    if (count($child
      ->getChildren()) > 0) {
      return false;
    }
    if (self::$root
      ->getName() === $path) {

      // delete root? very brave. :)
      self::$root = null;
      clearstatcache();
      return true;
    }
    $names = $this
      ->splitPath($path);
    $dir = $this
      ->getContentOfType($names['dirname'], vfsStreamContent::TYPE_DIR);
    if ($dir
      ->isWritable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {
      return false;
    }
    clearstatcache();
    return $dir
      ->removeChild($child
      ->getName());
  }

  /**
   * opens a directory
   *
   * @param   string  $path
   * @param   int     $options
   * @return  bool
   */
  public function dir_opendir($path, $options) {
    $path = $this
      ->resolvePath(vfsStream::path($path));
    $this->dir = $this
      ->getContentOfType($path, vfsStreamContent::TYPE_DIR);
    if (null === $this->dir || $this->dir
      ->isReadable(vfsStream::getCurrentUser(), vfsStream::getCurrentGroup()) === false) {
      return false;
    }
    $this->dirIterator = $this->dir
      ->getIterator();
    return true;
  }

  /**
   * reads directory contents
   *
   * @return  string
   */
  public function dir_readdir() {
    $dir = $this->dirIterator
      ->current();
    if (null === $dir) {
      return false;
    }
    $this->dirIterator
      ->next();
    return $dir
      ->getName();
  }

  /**
   * reset directory iteration
   *
   * @return  bool
   */
  public function dir_rewinddir() {
    return $this->dirIterator
      ->rewind();
  }

  /**
   * closes directory
   *
   * @return  bool
   */
  public function dir_closedir() {
    $this->dirIterator = null;
    return true;
  }

  /**
   * returns status of url
   *
   * @param   string  $path   path of url to return status for
   * @param   int     $flags  flags set by the stream API
   * @return  array
   */
  public function url_stat($path, $flags) {
    $content = $this
      ->getContent($this
      ->resolvePath(vfsStream::path($path)));
    if (null === $content) {
      if (($flags & STREAM_URL_STAT_QUIET) != STREAM_URL_STAT_QUIET) {
        trigger_error(' No such file or directory: ' . $path, E_USER_WARNING);
      }
      return false;
    }
    $fileStat = array(
      'dev' => 0,
      'ino' => 0,
      'mode' => $content
        ->getType() | $content
        ->getPermissions(),
      'nlink' => 0,
      'uid' => $content
        ->getUser(),
      'gid' => $content
        ->getGroup(),
      'rdev' => 0,
      'size' => $content
        ->size(),
      'atime' => $content
        ->fileatime(),
      'mtime' => $content
        ->filemtime(),
      'ctime' => $content
        ->filectime(),
      'blksize' => -1,
      'blocks' => -1,
    );
    return array_merge(array_values($fileStat), $fileStat);
  }

}

Classes

Namesort descending Description
vfsStreamWrapper Stream wrapper to mock file system requests.