Skip to content

Instantly share code, notes, and snippets.

@fly2xiang
Created April 18, 2018 09:01
Show Gist options
  • Save fly2xiang/077cc2eb2e92790a72e82f796f88a3e0 to your computer and use it in GitHub Desktop.
Save fly2xiang/077cc2eb2e92790a72e82f796f88a3e0 to your computer and use it in GitHub Desktop.
PHP StreamWrapper TempFS
<?php
class TempFS {
/**
* @var $context resource
*/
public $context;
/**
* @var $store array
*/
private static $store = array(
'usr' => array(
'local' => array(
'php' => array(
'bin' => array(
'php' => 'content of php'
)
)
)
)
);
/**
* @var $protocol string
*/
private static $protocol = 'tempfs';
/**
* @var $pathPrefix string
*/
private static $pathPrefix;
/**
* @var $position int
*/
private $position;
/**
* @var $dir_index int
*/
private $dir_index = 0;
/**
* @var $path string
*/
private $path;
/**
* 初始化
*/
public static function init() {
stream_wrapper_register(self::$protocol, 'TempFS');
self::$pathPrefix = self::$protocol . '://';
}
public static function log($function, $arguments) {
echo $function . '('. implode(', ', $arguments) .')' . PHP_EOL;
}
/**
* streamWrapper constructor.
*/
public function __construct() {
echo PHP_EOL . '========================================' . PHP_EOL;
self::log(__METHOD__, func_get_args());
}
/**
*
*/
public function __destruct() {
self::log(__METHOD__, func_get_args());
echo '========================================' . PHP_EOL . PHP_EOL;
}
/**
* @return bool
*/
public function dir_closedir() {
self::log(__METHOD__, func_get_args());
return true;
}
/**
* @param string $path
* @param int $options
* @return bool
*/
public function dir_opendir($path, $options) {
self::log(__METHOD__, func_get_args());
if (strpos($path, self::$pathPrefix) !== 0) {
return false;
}
$path = '/' . substr($path, strlen(self::$pathPrefix));
$this->path = $this->get_absolute_path($path);
return true;
}
/**
* @return string
*/
public function dir_readdir() {
self::log(__METHOD__, func_get_args());
$paths = explode(DIRECTORY_SEPARATOR, $this->path);
$store = &self::$store;
foreach ($paths as $item) {
$store = &$store[$item];
}
unset($item);
if ($this->dir_index - 2 >= count($store)) {
return false;
}
if ($this->dir_index === 0) {
$this->dir_index ++;
return '.';
}
if ($this->dir_index === 1) {
$this->dir_index ++;
return '..';
}
$index = 0;
foreach ($store as $item => $value) {
if ($index >= $this->dir_index - 2) {
break;
}
$index ++;
}
$this->dir_index ++;
return $item;
}
/**
* @param
* @return bool
*/
public function dir_rewinddir() {
self::log(__METHOD__, func_get_args());
$this->dir_index = 2;
return true;
}
/**
* @param string $path
* @param int $mode
* @param int $options
* @return bool
*/
public function mkdir($path, $mode , $options) {
self::log(__METHOD__, func_get_args());
if (strpos($path, self::$pathPrefix) !== 0) {
return false;
}
$path = '/' . substr($path, strlen(self::$pathPrefix));
$path = $this->get_absolute_path($path);
$paths = explode(DIRECTORY_SEPARATOR, $path);
$store = &self::$store;
foreach ($paths as $item) {
if (! isset($store[$item])) {
$store[$item] = array();
}
$store = &$store[$item];
}
unset($item);
return true;
}
/**
* @param string $path_from
* @param string $path_to
* @return bool
*/
public function rename($path_from, $path_to) {
self::log(__METHOD__, func_get_args());
return true;
}
/**
* @param string $path
* @param int $options
* @return bool
*/
public function rmdir($path, $options) {
self::log(__METHOD__, func_get_args());
if (strpos($path, self::$pathPrefix) !== 0) {
return false;
}
$path = '/' . substr($path, strlen(self::$pathPrefix));
$path = $this->get_absolute_path($path);
$paths = explode(DIRECTORY_SEPARATOR, $path);
$last = array_pop($paths);
$store = &self::$store;
foreach ($paths as $item) {
$store = &$store[$item];
}
unset($item);
unset($store[$last]);
return true;
}
/**
* @param int $cast_as
* @return resource
*/
public function stream_cast($cast_as) {
self::log(__METHOD__, func_get_args());
return $this->context;
}
/**
*
*/
public function stream_close() {
self::log(__METHOD__, func_get_args());
}
/**
* @return bool
*/
public function stream_eof() {
self::log(__METHOD__, func_get_args());
$contents = $this->get_file_contents($this->path);
if ($this->position >= strlen($contents)) {
return true;
}
return false;
}
/**
* @return bool
*/
public function stream_flush() {
self::log(__METHOD__, func_get_args());
return true;
}
/**
* @param int $operation
* @return bool
*/
public function stream_lock($operation) {
self::log(__METHOD__, func_get_args());
return true;
}
/**
* @param string $path
* @param int $option
* @param mixed $value
* @return bool
*/
public function stream_metadata($path, $option, $value) {
self::log(__METHOD__, func_get_args());
return true;
}
/**
* @param string $path
* @param string $mode
* @param int $options
* @param string $opened_path
* @return bool
*/
public function stream_open($path, $mode, $options, &$opened_path) {
self::log(__METHOD__, func_get_args());
if (strpos($path, self::$pathPrefix) !== 0) {
return false;
}
$path = '/' . substr($path, strlen(self::$pathPrefix));
$this->path = $this->get_absolute_path($path);
$opened_path = $path;
return true;
}
/**
* @param int $count
* @return string
*/
public function stream_read($count) {
self::log(__METHOD__, func_get_args());
$contents = $this->get_file_contents($this->path);
$read = substr($contents, $this->position, $count);
$this->position += strlen($read);
return $read;
}
private function get_file_contents($path) {
$paths = explode(DIRECTORY_SEPARATOR, $path);
$store = &self::$store;
foreach ($paths as $item) {
$store = &$store[$item];
}
unset($item);
return $store;
}
/**
* @param int $offset
* @param int $whence
* @return bool
*/
public function stream_seek($offset, $whence = SEEK_SET) {
self::log(__METHOD__, func_get_args());
switch ($whence) {
case SEEK_SET:
$this->position = $offset;
break;
case SEEK_CUR:
$this->position += $offset;
break;
case SEEK_END:
$contents = $this->get_file_contents($this->path);
$this->position = strlen($contents) + $offset;
break;
default:
break;
}
return true;
}
/**
* @param int $option
* @param int $arg1
* @param int $arg2
* @return bool
*/
public function stream_set_option($option, $arg1, $arg2) {
self::log(__METHOD__, func_get_args());
return true;
}
/**
* @return array
*/
public function stream_stat() {
self::log(__METHOD__, func_get_args());
$contents = $this->get_file_contents($this->path);
$size = strlen($contents);
return array (
0 => 64784,
1 => 12359930,
2 => 33204,
3 => 1,
4 => 503,
5 => 505,
6 => 0,
7 => $size,
8 => 1524022278,
9 => 1524022277,
10 => 1524022277,
11 => 4096,
12 => 8,
'dev' => 64784,
'ino' => 12359930,
'mode' => 33204,
'nlink' => 1,
'uid' => 503,
'gid' => 505,
'rdev' => 0,
'size' => $size,
'atime' => 1524022278,
'mtime' => 1524022277,
'ctime' => 1524022277,
'blksize' => 4096,
'blocks' => 8,
);
}
/**
* @return int
*/
public function stream_tell() {
self::log(__METHOD__, func_get_args());
return 0;
}
/**
* @param int $new_size
* @return bool
*/
public function stream_truncate($new_size) {
self::log(__METHOD__, func_get_args());
$paths = explode(DIRECTORY_SEPARATOR, $this->path);
$last = array_pop($paths);
$store = &self::$store;
foreach ($paths as $item) {
$store = &$store[$item];
}
unset($item);
$store[$last] = substr($store[$last], 0, $new_size);
return true;
}
/**
* @param string $data
* @return int
*/
public function stream_write($data) {
self::log(__METHOD__, func_get_args());
$len = strlen($data);
$paths = explode(DIRECTORY_SEPARATOR, $this->path);
$last = array_pop($paths);
$store = &self::$store;
foreach ($paths as $item) {
$store = &$store[$item];
}
unset($item);
$store[$last] = substr_replace($store[$last], $data, $this->position, $len);
$this->position += $len;
return $len;
}
/**
* @param string $path
* @return bool
*/
public function unlink($path) {
self::log(__METHOD__, func_get_args());
return true;
}
/**
* @param string $path
* @param int $flags
* @return array
*/
public function url_stat($path, $flags) {
self::log(__METHOD__, func_get_args());
$contents = $this->get_file_contents($this->path);
$size = strlen($contents);
return array (
0 => 64784,
1 => 12359930,
2 => 33204,
3 => 1,
4 => 503,
5 => 505,
6 => 0,
7 => $size,
8 => 1524022278,
9 => 1524022277,
10 => 1524022277,
11 => 4096,
12 => 8,
'dev' => 64784,
'ino' => 12359930,
'mode' => 33204,
'nlink' => 1,
'uid' => 503,
'gid' => 505,
'rdev' => 0,
'size' => $size,
'atime' => 1524022278,
'mtime' => 1524022277,
'ctime' => 1524022277,
'blksize' => 4096,
'blocks' => 8,
);
}
private function get_absolute_path($path) {
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
$absolutes = array();
foreach ($parts as $part) {
if ('.' == $part) continue;
if ('..' == $part) {
array_pop($absolutes);
} else {
$absolutes[] = $part;
}
}
return implode(DIRECTORY_SEPARATOR, $absolutes);
}
public static function dumpStore() {
var_dump(self::$store);
}
}
TempFS::init();
// ZipArchive 不支持 streamwrapper, 所以使用 PHPExcel 不能读取 streamwrapper 中的 xlsx 文件 (但支持 xls)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment