Created
April 18, 2018 09:01
-
-
Save fly2xiang/077cc2eb2e92790a72e82f796f88a3e0 to your computer and use it in GitHub Desktop.
PHP StreamWrapper TempFS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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