Last active
August 29, 2015 14:23
-
-
Save chx/0db97d97661b50381907 to your computer and use it in GitHub Desktop.
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 | |
/** | |
* @file | |
* Contains \Drupal\Core\StreamWrapper\FileDatabaseStream. | |
*/ | |
namespace Drupal\Core\StreamWrapper; | |
use Drupal\Core\KeyValueStore\KeyValueStoreInterface; | |
class PharDatabaseStream { | |
// This file doesn't exist. When you try reading | |
// phar://./drupal-phpstorage.phar/something.php the value will be read from | |
// a K-V store. The key will be a hash of a secret and "something.php". | |
const MAGIC_NAME = 'phar://./drupal-phpstorage.phar/'; | |
/** | |
* Stream context resource. | |
* | |
* @var resource | |
*/ | |
public $context = NULL; | |
/** | |
* A generic resource handle. | |
* | |
* @var resource | |
*/ | |
public $handle = NULL; | |
/** | |
* @var KeyValueStoreInterface | |
*/ | |
protected $storage; | |
/** | |
* @var string | |
*/ | |
protected $key; | |
public function __construct(KeyValueStoreInterface $storage, $secret) { | |
$this->storage = $storage; | |
$this->secret = $secret; | |
} | |
public function dir_closedir() { | |
closedir($this->handle); | |
return TRUE; | |
} | |
public function dir_opendir($path, $options) { | |
$this->usePhpWrapper(); | |
$this->key = ''; | |
$this->handle = opendir($path, $this->context); | |
$this->useOurWrapper(); | |
return (bool) $this->handle; | |
} | |
public function dir_readdir() { | |
return readdir($this->handle); | |
} | |
public function dir_rewinddir() { | |
rewinddir($this->handle); | |
} | |
public function mkdir($path, $mode, $options) { | |
$this->usePhpWrapper(); | |
$return = mkdir($path, $mode, $options); | |
$this->useOurWrapper(); | |
return $return; | |
} | |
public function rename($path_from, $path_to) { | |
$this->usePhpWrapper(); | |
$return = rename($path_from, $path_to); | |
$this->useOurWrapper(); | |
return $return; | |
} | |
public function rmdir($path, $options) { | |
$this->usePhpWrapper(); | |
$return = rmdir($path, $options); | |
$this->useOurWrapper(); | |
return $return; | |
} | |
public function stream_cast($cast_as) { | |
return $this->handle ? $this->handle : FALSE; | |
} | |
public function stream_close () { | |
if ($this->key) { | |
fseek($this->handle, 0); | |
$buf = ''; | |
while (!feof($this->handle)) { | |
$buf .= fread($this->handle, 1048576); | |
} | |
$this->storage->setMultiple([ | |
$this->key => $buf, | |
"$this->key:mtime" => time(), | |
"$this->key:size" => strlen($buf), | |
]); | |
} | |
return fclose($this->handle); | |
} | |
public function stream_eof() { | |
return feof($this->handle); | |
} | |
public function stream_flush() { | |
return fflush($this->handle); | |
} | |
public function stream_lock($operation) { | |
return flock($this->handle, $operation); | |
} | |
public function stream_metadata($path, $option, $value) { | |
$this->usePhpWrapper(); | |
$return = LocalStream::metadata($path, $option, $value); | |
$this->useOurWrapper(); | |
return $return; | |
} | |
public function stream_open($path, $mode, $options, &$opened_path) { | |
$this->key = ''; | |
if ($filename = $this->getFilename($path)) { | |
$this->handle = $this->openFromStorage($filename, $mode); | |
} | |
else { | |
$this->usePhpWrapper(); | |
$this->handle = fopen($path, $mode, $options & STREAM_USE_PATH, $this->context); | |
$this->useOurWrapper(); | |
} | |
// @TODO is this necessary? | |
if ($this->handle) { | |
$opened_path = $path; | |
return TRUE; | |
} | |
return FALSE; | |
} | |
public function stream_read($count) { | |
return fread($this->handle, $count); | |
} | |
public function stream_seek($offset, $whence = SEEK_SET) { | |
return fseek($this->handle, $offset, $whence); | |
} | |
public function stream_set_option($option, $arg1, $arg2) { | |
switch ($option) { | |
case STREAM_OPTION_BLOCKING: | |
return stream_set_blocking($this->handle, $arg1); | |
case STREAM_OPTION_READ_TIMEOUT: | |
return stream_set_timeout($this->handle, $arg1, $arg2); | |
case STREAM_OPTION_WRITE_BUFFER: | |
return stream_set_write_buffer($this->handle, $arg1); | |
case STREAM_OPTION_READ_BUFFER: | |
return stream_set_read_buffer($this->handle, $arg1); | |
} | |
} | |
public function stream_stat() { | |
return fstat($this->handle); | |
} | |
public function stream_tell() { | |
return ftell($this->handle); | |
} | |
public function stream_truncate($new_size) { | |
return ftruncate($this->handle, $new_size); | |
} | |
public function stream_write ($data) { | |
return fwrite($this->handle, $data); | |
} | |
public function unlink($path) { | |
$this->usePhpWrapper(); | |
$return = unlink($path, $this->context); | |
$this->useOurWrapper(); | |
return $return; | |
} | |
public function url_stat($path, $flags) { | |
if ($flags & STREAM_URL_STAT_QUIET) { | |
set_error_handler(function() {}); | |
} | |
$this->usePhpWrapper(); | |
if ($filename = $this->getFilename($path)) { | |
$return = $this->statFromStorage($filename); | |
} | |
else { | |
$return = stat($path); | |
} | |
$this->useOurWrapper(); | |
if ($flags & STREAM_URL_STAT_QUIET) { | |
restore_error_handler(); | |
} | |
return $return; | |
} | |
protected function usePhpWrapper() { | |
stream_wrapper_restore('phar'); | |
} | |
protected function useOurWrapper() { | |
stream_wrapper_register('phar', get_called_class()); | |
} | |
protected function getFilename($path) { | |
$n = strlen(static::MAGIC_NAME); | |
if (substr($path, 0, $n) === static::MAGIC_NAME) { | |
return substr($path, $n); | |
} | |
return FALSE; | |
} | |
/** | |
* @param $filename | |
* @param $mode | |
* | |
* @return resource|FALSE | |
*/ | |
protected function openFromStorage($filename, $mode) { | |
$handle = FALSE; | |
$key = $this->getKeyFromFilename($filename); | |
$data = $this->storage->getMultiple($key); | |
if (isset($data[$key])) { | |
if ($mode !== 'r') { | |
$this->key = $key; | |
} | |
$handle = fopen('php://memory', 'rw'); | |
fwrite($this->handle, $data[$key]); | |
fseek($this->handle, 0); | |
} | |
return $handle; | |
} | |
/** | |
* @return array | |
*/ | |
protected function statFromStorage($filename) { | |
$key = $this->getKeyFromFilename($filename); | |
$return = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1]; | |
$data = $this->storage->getMultiple(["$key:size", "$key:mtime"]); | |
if (count($data) == 2) { | |
$return[7] = $data["$key:size"]; | |
$return[9] = $data["$key:mtime"]; | |
} | |
return $return; | |
} | |
/** | |
* @param $filename | |
* @return string | |
*/ | |
protected function getKeyFromFilename($filename) { | |
return hash_hmac('sha256', $filename, $this->secret); | |
} | |
} |
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
diff --git a/core/lib/Drupal/Core/StreamWrapper/LocalStream.php b/core/lib/Drupal/Core/StreamWrapper/LocalStream.php | |
index 7720655..5bf4bcb 100644 | |
--- a/core/lib/Drupal/Core/StreamWrapper/LocalStream.php | |
+++ b/core/lib/Drupal/Core/StreamWrapper/LocalStream.php | |
@@ -50,6 +50,46 @@ public static function getType() { | |
} | |
/** | |
+ * @param $target | |
+ * @param $option | |
+ * @param $value | |
+ * @return bool | |
+ */ | |
+ public static function metadata($target, $option, $value) { | |
+ $return = FALSE; | |
+ switch ($option) { | |
+ case STREAM_META_TOUCH: | |
+ if (!empty($value)) { | |
+ $return = touch($target, $value[0], $value[1]); | |
+ } | |
+ else { | |
+ $return = touch($target); | |
+ } | |
+ break; | |
+ | |
+ case STREAM_META_OWNER_NAME: | |
+ case STREAM_META_OWNER: | |
+ $return = chown($target, $value); | |
+ break; | |
+ | |
+ case STREAM_META_GROUP_NAME: | |
+ case STREAM_META_GROUP: | |
+ $return = chgrp($target, $value); | |
+ break; | |
+ | |
+ case STREAM_META_ACCESS: | |
+ $return = chmod($target, $value); | |
+ break; | |
+ } | |
+ if ($return) { | |
+ // For convenience clear the file status cache of the underlying file, | |
+ // since metadata operations are often followed by file status checks. | |
+ clearstatcache(TRUE, $target); | |
+ } | |
+ return $return; | |
+ } | |
+ | |
+ /** | |
* Gets the path that the wrapper is responsible for. | |
* | |
* @todo Review this method name in D8 per https://www.drupal.org/node/701358. | |
@@ -304,37 +344,7 @@ public function stream_cast($cast_as) { | |
*/ | |
public function stream_metadata($uri, $option, $value) { | |
$target = $this->getLocalPath($uri); | |
- $return = FALSE; | |
- switch ($option) { | |
- case STREAM_META_TOUCH: | |
- if (!empty($value)) { | |
- $return = touch($target, $value[0], $value[1]); | |
- } | |
- else { | |
- $return = touch($target); | |
- } | |
- break; | |
- | |
- case STREAM_META_OWNER_NAME: | |
- case STREAM_META_OWNER: | |
- $return = chown($target, $value); | |
- break; | |
- | |
- case STREAM_META_GROUP_NAME: | |
- case STREAM_META_GROUP: | |
- $return = chgrp($target, $value); | |
- break; | |
- | |
- case STREAM_META_ACCESS: | |
- $return = chmod($target, $value); | |
- break; | |
- } | |
- if ($return) { | |
- // For convenience clear the file status cache of the underlying file, | |
- // since metadata operations are often followed by file status checks. | |
- clearstatcache(TRUE, $target); | |
- } | |
- return $return; | |
+ return static::metadata($target, $option, $value); | |
} | |
/** |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment