Seditio Source
Root |
./othercms/drupal-7.90/misc/typo3/phar-stream-wrapper/src/PharStreamWrapper.php
<?php
namespace TYPO3\PharStreamWrapper;

/*
 * This file is part of the TYPO3 project.
 *
 * It is free software; you can redistribute it and/or modify it under the terms
 * of the MIT License (MIT). For the full copyright and license information,
 * please read the LICENSE file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

use TYPO3\PharStreamWrapper\Resolver\PharInvocation;

class
PharStreamWrapper
{
   
/**
     * Internal stream constants that are not exposed to PHP, but used...
     * @see https://github.com/php/php-src/blob/e17fc0d73c611ad0207cac8a4a01ded38251a7dc/main/php_streams.h
     */
   
const STREAM_OPEN_FOR_INCLUDE = 128;

   
/**
     * @var resource
     */
   
public $context;

   
/**
     * @var resource
     */
   
protected $internalResource;

   
/**
     * @var PharInvocation
     */
   
protected $invocation;

   
/**
     * @return bool
     */
   
public function dir_closedir()
    {
        if (!
is_resource($this->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));
    }
}