diff --git a/stream_wrapper_example/src/Controller/ExampleController.php b/stream_wrapper_example/src/Controller/ExampleController.php deleted file mode 100644 index 437fd7d..0000000 --- a/stream_wrapper_example/src/Controller/ExampleController.php +++ /dev/null @@ -1,30 +0,0 @@ - [ - '#theme' => 'example_description', - ], - ]; - return $build; - } - -} - diff --git a/stream_wrapper_example/src/PathProcessor/PathProcessorSessions.php b/stream_wrapper_example/src/PathProcessor/PathProcessorSessions.php deleted file mode 100644 index 33addab..0000000 --- a/stream_wrapper_example/src/PathProcessor/PathProcessorSessions.php +++ /dev/null @@ -1,35 +0,0 @@ -query->has('file')) { - $file_path = preg_replace('|^\/examples\/stream_wrapper_example\/files\/|', '', $path); - $request->query->set('file', $file_path); - // We return the route we want to match. - return '/examples/stream_wrapper_example/files'; - } - return $path; - } - -} diff --git a/stream_wrapper_example/src/StreamWrapper/FileExampleSessionStreamWrapper.php b/stream_wrapper_example/src/StreamWrapper/FileExampleSessionStreamWrapper.php deleted file mode 100644 index 30d6e48..0000000 --- a/stream_wrapper_example/src/StreamWrapper/FileExampleSessionStreamWrapper.php +++ /dev/null @@ -1,867 +0,0 @@ -requestStack = \Drupal::service('request_stack'); - $helper = $this->getSessionWrapper(); - $helper->setPath('.isadir.txt', TRUE); - $this->streamMode = FALSE; - } - - /** - * Get wrapped session manipulators. - */ - public function getSessionWrapper() { - return new SessionWrapper($this->requestStack); - } - - /** - * Returns the name of the stream wrapper for use in the UI. - * - * @return string - * The stream wrapper name. - */ - public function getName() { - return t('File Example Session files'); - } - - /** - * {@inheritdoc} - */ - public function getDescription() { - return t('Simulated file system using your session storage. Not for real use!'); - } - - - /** - * Implements setUri(). - */ - public function setUri($uri) { - $this->uri = $uri; - } - - /** - * Implements getUri(). - */ - public function getUri() { - return $this->uri; - } - - /** - * Implements getTarget(). - * - * The "target" is the portion of the URI to the right of the scheme. - * So in session://example/test.txt, the target is 'example/test.txt'. - * - * @todo Figure out what this is in the new API. - */ - public function getTarget($uri = NULL) { - if (!isset($uri)) { - $uri = $this->uri; - } - - list($scheme, $target) = explode('://', $uri, 2); - - // Remove erroneous leading or trailing, forward-slashes and backslashes. - // In the session:// scheme, there is never a leading slash on the target. - return trim($target, '\/'); - } - - /** - * Implements getDirectoryPath(). - * - * In this case there is no directory string, so return an empty string. - */ - public function getDirectoryPath() { - return ''; - } - - /** - * Overrides getExternalUrl(). - * - * We have set up a helper function and menu entry to provide access to this - * key via HTTP; normally it would be accessible some other way. - */ - public function getExternalUrl() { - $path = str_replace('\\', '/', $this->getTarget()); - return $this->url('stream_wrapper_example.files.session', ['filepath' => $path, 'scheme' => 'session'], ['absolute' => TRUE]); - } - - /** - * Returns canonical, absolute path of the resource. - * - * Implementation placeholder. PHP's realpath() does not support stream - * wrappers. We provide this as a default so that individual wrappers may - * implement their own solutions. - * - * @return string - * Returns a string with absolute pathname on success (implemented - * by core wrappers), or FALSE on failure or if the registered - * wrapper does not provide an implementation. - */ - public function realpath() { - return 'session://' . $this->getLocalPath(); - } - - /** - * Returns the local path. - * - * Here we aren't doing anything but stashing the "file" in a key in the - * $_SESSION variable, so there's not much to do but to create a "path" - * which is really just a key in the $_SESSION variable. So something - * like 'session://one/two/three.txt' becomes - * $_SESSION['stream_wrapper_example']['one']['two']['three.txt'] and the actual path - * is "one/two/three.txt". - * - * @param string $uri - * Optional URI, supplied when doing a move or rename. - */ - protected function getLocalPath($uri = NULL) { - if (!isset($uri)) { - $uri = $this->uri; - } - - $path = str_replace('session://', '', $uri); - $path = trim($path, '/'); - return $path; - } - - /** - * Opens a stream, as for fopen(), file_get_contents(), file_put_contents(). - * - * @param string $uri - * A string containing the URI to the file to open. - * @param string $mode - * The file mode ("r", "wb" etc.). - * @param int $options - * A bit mask of STREAM_USE_PATH and STREAM_REPORT_ERRORS. - * @param string &$opened_path - * A string containing the path actually opened. - * - * @return bool - * Returns TRUE if file was opened successfully. (Always returns TRUE). - * - * @see http://php.net/manual/en/streamwrapper.stream-open.php - */ - public function stream_open($uri, $mode, $options, &$opened_path) { - $this->uri = $uri; - $path = $this->getLocalPath($uri); - // We will support two modes only, 'r' and 'w'. If the key is 'r', - // check to make sure the file is there. - if (stristr($mode, 'r') !== FALSE) { - $helper = $this->getSessionWrapper(); - if (!$helper->checkPath($path)) { - return FALSE; - } - else { - $buffer = $helper->getPath($path); - if (!is_string($buffer)) { - return FALSE; - } - $this->sessionContent = $buffer; - } - $this->streamMode = 'r'; - } - else { - $this->sessionContent = ''; - $this->streamMode = 'w'; - } - // Reset the stream pointer since this is an open. - $this->streamPointer = 0; - return TRUE; - } - - /** - * Retrieve the underlying stream resource. - * - * This method is called in response to stream_select(). - * - * @param int $cast_as - * Can be STREAM_CAST_FOR_SELECT when stream_select() is calling - * stream_cast() or STREAM_CAST_AS_STREAM when stream_cast() is called for - * other uses. - * - * @return resource|false - * The underlying stream resource or FALSE if stream_select() is not - * supported. - * - * @see stream_select() - * @see http://php.net/manual/streamwrapper.stream-cast.php - */ - public function stream_cast($cast_as) { - return FALSE; - } - - /** - * Sets metadata on the stream. - * - * @param string $path - * A string containing the URI to the file to set metadata on. - * @param int $option - * One of: - * - STREAM_META_TOUCH: The method was called in response to touch(). - * - STREAM_META_OWNER_NAME: The method was called in response to chown() - * with string parameter. - * - STREAM_META_OWNER: The method was called in response to chown(). - * - STREAM_META_GROUP_NAME: The method was called in response to chgrp(). - * - STREAM_META_GROUP: The method was called in response to chgrp(). - * - STREAM_META_ACCESS: The method was called in response to chmod(). - * @param mixed $value - * If option is: - * - STREAM_META_TOUCH: Array consisting of two arguments of the touch() - * function. - * - STREAM_META_OWNER_NAME or STREAM_META_GROUP_NAME: The name of the owner - * user/group as string. - * - STREAM_META_OWNER or STREAM_META_GROUP: The value of the owner - * user/group as integer. - * - STREAM_META_ACCESS: The argument of the chmod() as integer. - * - * @return bool - * Returns TRUE on success or FALSE on failure. If $option is not - * implemented, FALSE should be returned. - * - * @see http://www.php.net/manual/streamwrapper.stream-metadata.php - */ - public function stream_metadata($path, $option, $value) { - // We don't really do any of these, but we want to reassure the calling code - // that there is no problem with chown or chgrp, even though we do not - // actually support these. - return TRUE; - } - - - /** - * Change stream options. - * - * This method is called to set options on the stream. - * - * @param int $option - * One of: - * - STREAM_OPTION_BLOCKING: The method was called in response to - * stream_set_blocking(). - * - STREAM_OPTION_READ_TIMEOUT: The method was called in response to - * stream_set_timeout(). - * - STREAM_OPTION_WRITE_BUFFER: The method was called in response to - * stream_set_write_buffer(). - * @param int $arg1 - * If option is: - * - STREAM_OPTION_BLOCKING: The requested blocking mode: - * - 1 means blocking. - * - 0 means not blocking. - * - STREAM_OPTION_READ_TIMEOUT: The timeout in seconds. - * - STREAM_OPTION_WRITE_BUFFER: The buffer mode, STREAM_BUFFER_NONE or - * STREAM_BUFFER_FULL. - * @param int $arg2 - * If option is: - * - STREAM_OPTION_BLOCKING: This option is not set. - * - STREAM_OPTION_READ_TIMEOUT: The timeout in microseconds. - * - STREAM_OPTION_WRITE_BUFFER: The requested buffer size. - * - * @return bool - * TRUE on success, FALSE otherwise. If $option is not implemented, FALSE - * should be returned. - */ - public function stream_set_option($option, $arg1, $arg2) { - return FALSE; - } - - /** - * Truncate stream. - * - * Will respond to truncation; e.g., through ftruncate(). - * - * @param int $new_size - * The new size. - * - * @return bool - * TRUE on success, FALSE otherwise. - * - * @todo - * This one actually makes sense for the example. - */ - public function stream_truncate($new_size) { - return FALSE; - } - - /** - * Support for flock(). - * - * The $_SESSION variable has no locking capability, so return TRUE. - * - * @param int $operation - * One of the following: - * - LOCK_SH to acquire a shared lock (reader). - * - LOCK_EX to acquire an exclusive lock (writer). - * - LOCK_UN to release a lock (shared or exclusive). - * - LOCK_NB if you don't want flock() to block while locking (not - * supported on Windows). - * - * @return bool - * Always returns TRUE at the present time. (no support) - * - * @see http://php.net/manual/en/streamwrapper.stream-lock.php - */ - public function stream_lock($operation) { - return TRUE; - } - - /** - * Support for fread(), file_get_contents() etc. - * - * @param int $count - * Maximum number of bytes to be read. - * - * @return string - * The string that was read, or FALSE in case of an error. - * - * @see http://php.net/manual/en/streamwrapper.stream-read.php - */ - public function stream_read($count) { - if (is_string($this->sessionContent)) { - $remaining_chars = strlen($this->sessionContent) - $this->streamPointer; - $number_to_read = min($count, $remaining_chars); - if ($remaining_chars > 0) { - $buffer = substr($this->sessionContent, $this->streamPointer, $number_to_read); - $this->streamPointer += $number_to_read; - return $buffer; - } - } - return FALSE; - } - - /** - * Support for fwrite(), file_put_contents() etc. - * - * @param string $data - * The string to be written. - * - * @return int - * The number of bytes written (integer). - * - * @see http://php.net/manual/en/streamwrapper.stream-write.php - */ - public function stream_write($data) { - // Sanitize the data in a simple way since we're putting it into the - // session variable. - $data = Html::escape($data); - $this->sessionContent = substr_replace($this->sessionContent, $data, $this->streamPointer); - $this->streamPointer += strlen($data); - return strlen($data); - } - - /** - * Support for feof(). - * - * @return bool - * TRUE if end-of-file has been reached. - * - * @see http://php.net/manual/en/streamwrapper.stream-eof.php - */ - public function stream_eof() { - return FALSE; - } - - /** - * Support for fseek(). - * - * @param int $offset - * The byte offset to got to. - * @param int $whence - * SEEK_SET, SEEK_CUR, or SEEK_END. - * - * @return bool - * TRUE on success. - * - * @see http://php.net/manual/en/streamwrapper.stream-seek.php - */ - public function stream_seek($offset, $whence = SEEK_SET) { - if (strlen($this->sessionContent) >= $offset) { - $this->streamPointer = $offset; - return TRUE; - } - return FALSE; - } - - /** - * Support for fflush(). - * - * @return bool - * TRUE if data was successfully stored (or there was no data to store). - * This always returns TRUE, as this example provides and needs no - * flush support. - * - * @see http://php.net/manual/en/streamwrapper.stream-flush.php - */ - public function stream_flush() { - if ($this->streamMode == 'w') { - // Since we aren't writing directly to the session, we need to send - // the bytes on to the store. - $helper = $this->getSessionWrapper(); - $path = $this->getLocalPath($this->uri); - $helper->setPath($path, $this->sessionContent); - $this->sessionContent = ''; - $this->streamPointer = 0; - } - return TRUE; - } - - /** - * Support for ftell(). - * - * @return int - * The current offset in bytes from the beginning of file. - * - * @see http://php.net/manual/en/streamwrapper.stream-tell.php - */ - public function stream_tell() { - return $this->streamPointer; - } - - /** - * Support for fstat(). - * - * @return array - * An array with file status, or FALSE in case of an error - see fstat() - * for a description of this array. - * - * @see http://php.net/manual/en/streamwrapper.stream-stat.php - */ - public function stream_stat() { - return array( - 'size' => strlen($this->sessionContent), - ); - } - - /** - * Support for fclose(). - * - * @return bool - * TRUE if stream was successfully closed. - * - * @see http://php.net/manual/en/streamwrapper.stream-close.php - */ - public function stream_close() { - $this->streamPointer = 0; - // Unassign the reference. - unset($this->sessionContent); - return TRUE; - } - - /** - * Support for unlink(). - * - * @param string $uri - * A string containing the uri to the resource to delete. - * - * @return bool - * TRUE if resource was successfully deleted. - * - * @see http://php.net/manual/en/streamwrapper.unlink.php - */ - public function unlink($uri) { - $path = $this->getLocalPath($uri); - $helper = $this->getSessionWrapper(); - $helper->clearPath($path); - return TRUE; - } - - /** - * Support for rename(). - * - * @param string $from_uri - * The uri to the file to rename. - * @param string $to_uri - * The new uri for file. - * - * @return bool - * TRUE if file was successfully renamed. - * - * @see http://php.net/manual/en/streamwrapper.rename.php - */ - public function rename($from_uri, $to_uri) { - // We get the old key contents, write it - // to a new key, erase the old key. - $from_path = $this->getLocalPath($from_uri); - $to_path = $this->getLocalPath($to_uri); - $helper = $this->getSessionWrapper(); - if (!$helper->checkPath($from_path)) { - return FALSE; - } - $from_key = $helper->getPath($from_path); - $path_info = $helper->getParentPath($to_path); - $parent_path = $path_info['dirname']; - $new_file = $path_info['basename']; - // We will only allow writing to a non-existent file - // in an existing directory. - if ($helper->checkPath($parent_path) && !$helper->checkPath($to_path)) { - $helper->setPath($to_path, $from_key); - $helper->clearPath($from_path); - return TRUE; - } - return FALSE; - } - - /** - * Gets the name of the directory from a given path. - * - * @param string $uri - * A URI. - * - * @return string - * A string containing the directory name. - * - * @see drupal_dirname() - */ - public function dirname($uri = NULL) { - list($scheme, $target) = explode('://', $uri, 2); - $target = $this->getTarget($uri); - if (strpos($target, '/')) { - $dirname = preg_replace('@/[^/]*$@', '', $target); - } - else { - $dirname = ''; - } - return $scheme . '://' . $dirname; - } - - /** - * Support for mkdir(). - * - * @param string $uri - * A string containing the URI to the directory to create. - * @param int $mode - * Permission flags - see mkdir(). - * @param int $options - * A bit mask of STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE. - * - * @return bool - * TRUE if directory was successfully created. - * - * @see http://php.net/manual/en/streamwrapper.mkdir.php - */ - public function mkdir($uri, $mode, $options) { - // If this already exists, then we can't mkdir. - if (is_dir($uri) || is_file($uri)) { - return FALSE; - } - $path = $this->getLocalPath($uri); - $helper = $this->getSessionWrapper(); - $new_dir = ['isadir.txt' => TRUE]; - $helper->setPath($path, $new_dir); - return TRUE; - } - - /** - * Support for rmdir(). - * - * @param string $uri - * A string containing the URI to the directory to delete. - * @param int $options - * A bit mask of STREAM_REPORT_ERRORS. - * - * @return bool - * TRUE if directory was successfully removed. - * - * @see http://php.net/manual/en/streamwrapper.rmdir.php - */ - public function rmdir($uri, $options) { - $path = $this->getLocalPath($uri); - $helper = $this->getSessionWrapper(); - if (!$helper->checkPath($path) or !is_array($helper->getPath($path))) { - return FALSE; - } - $helper->clearPath($path); - return TRUE; - } - - /** - * Support for stat(). - * - * This important function goes back to the Unix way of doing things. - * In this example almost the entire stat array is irrelevant, but the - * mode is very important. It tells PHP whether we have a file or a - * directory and what the permissions are. All that is packed up in a - * bitmask. This is not normal PHP fodder. - * - * @param string $uri - * A string containing the URI to get information about. - * @param int $flags - * A bit mask of STREAM_URL_STAT_LINK and STREAM_URL_STAT_QUIET. - * - * @return array|bool - * An array with file status, or FALSE in case of an error - see fstat() - * for a description of this array. - * - * @see http://php.net/manual/en/streamwrapper.url-stat.php - */ - public function url_stat($uri, $flags) { - $path = $this->getLocalPath($uri); - $helper = $this->getSessionWrapper(); - if (!$helper->checkPath($path)) { - return FALSE; - // No file. - } - // Default to fail. - $return = FALSE; - $mode = 0; - - $path_info = $helper->getParentPath($path); - $key = $helper->getPath($path); - $key_name = $path_info['basename']; - // We will call an array a directory and the root is always an array. - if (is_array($key)) { - // S_IFDIR means it's a directory. - $mode = 0040000; - } - elseif ($key !== FALSE) { - // S_IFREG, means it's a file. - $mode = 0100000; - } - - if ($mode) { - $size = 0; - if ($mode == 0100000) { - $size = strlen($key); - } - - // There are no protections on this, so all writable. - $mode |= 0777; - $return = array( - 'dev' => 0, - 'ino' => 0, - 'mode' => $mode, - 'nlink' => 0, - 'uid' => 0, - 'gid' => 0, - 'rdev' => 0, - 'size' => $size, - 'atime' => 0, - 'mtime' => 0, - 'ctime' => 0, - 'blksize' => 0, - 'blocks' => 0, - ); - } - return $return; - } - - /** - * Support for opendir(). - * - * @param string $uri - * A string containing the URI to the directory to open. - * @param int $options - * Whether or not to enforce safe_mode (0x04). - * - * @return bool - * TRUE on success. - * - * @see http://php.net/manual/en/streamwrapper.dir-opendir.php - */ - public function dir_opendir($uri, $options) { - $path = $this->getLocalPath($uri); - $helper = $this->getSessionWrapper(); - if (!$helper->checkPath($path)) { - return FALSE; - } - $var = $helper->getPath($path); - if (!is_array($var)) { - return FALSE; - } - - // We grab the list of key names, flip it so that .isadir.txt can easily - // be removed, then flip it back so we can easily walk it as a list. - $this->directoryKeys = array_flip(array_keys($var)); - unset($this->directoryKeys['.isadir.txt']); - $this->directoryKeys = array_keys($this->directoryKeys); - $this->directoryPointer = 0; - return TRUE; - } - - /** - * Support for readdir(). - * - * @return string|bool - * The next filename, or FALSE if there are no more files in the directory. - * - * @see http://php.net/manual/en/streamwrapper.dir-readdir.php - */ - public function dir_readdir() { - if ($this->directoryPointer < count($this->directoryKeys)) { - $next = $this->directoryKeys[$this->directoryPointer]; - $this->directoryPointer++; - return $next; - } - return FALSE; - } - - /** - * Support for rewinddir(). - * - * @return bool - * TRUE on success. - * - * @see http://php.net/manual/en/streamwrapper.dir-rewinddir.php - */ - public function dir_rewinddir() { - $this->directoryPointer = 0; - } - - /** - * Support for closedir(). - * - * @return bool - * TRUE on success. - * - * @see http://php.net/manual/en/streamwrapper.dir-closedir.php - */ - public function dir_closedir() { - $this->directoryPointer = 0; - unset($this->directoryKeys); - return TRUE; - } - -} diff --git a/stream_wrapper_example/src/StreamWrapper/MockSessionTrait.php b/stream_wrapper_example/src/StreamWrapper/MockSessionTrait.php deleted file mode 100644 index 9511748..0000000 --- a/stream_wrapper_example/src/StreamWrapper/MockSessionTrait.php +++ /dev/null @@ -1,101 +0,0 @@ -sessionStore = []; - $session = $this->prophesize(SessionInterface::class); - $test = $this; - - $session - ->get('stream_wrapper_example', []) - ->will(function($args) use ($test) { - return $test->getSessionStore(); - }); - - $session - ->set('stream_wrapper_example', Argument::any()) - ->will(function($args) use ($test) { - $test->setSessionStore($args[1]); - }); - - $session - ->remove('stream_wrapper_example') - ->will(function($args) use ($test) { - $test->resetSessionStore(); - }); - - $request = $this->prophesize(Request::class); - $request - ->getSession() - ->willReturn($session->reveal()); - - $request_stack = $this->prophesize(RequestStack::class); - $request_stack - ->getCurrentRequest() - ->willReturn($request->reveal()); - - return $this->requestStack = $request_stack->reveal(); - } - - /** - * Get a session wrapper. - */ - public function getSessionWrapper() { - return new SessionWrapper($this->requestStack); - } - - /** - * Helper for mocks. - */ - public function getSessionStore() { - return $this->sessionStore; - } - - /** - * Helper for our mocks. - */ - public function setSessionStore($data) { - $this->sessionStore = $data; - } - - /** - * Helper for our mocks. - */ - public function resetSessionStore() { - $this->sessionStore = []; - } - -} diff --git a/stream_wrapper_example/src/StreamWrapper/SessionWrapper.php b/stream_wrapper_example/src/StreamWrapper/SessionWrapper.php deleted file mode 100644 index 02c9332..0000000 --- a/stream_wrapper_example/src/StreamWrapper/SessionWrapper.php +++ /dev/null @@ -1,251 +0,0 @@ -requestStack = $request_stack; - $this->storePath = ''; - } - - - /** - * Get a fresh session object. - * - * @return SessionInterface - * A session object. - */ - protected function getSession() { - return $this->requestStack->getCurrentRequest()->getSession(); - } - - /** - * Get whatever's in the store. - * - * @return array - * An associated array where scalar data represents file, and arrays represent directories. - */ - protected function getStore() { - $session = $this->getSession(); - $store = $session->get(static::SESSION_BASE_ATTRIBUTE, []); - return $store; - } - - /** - * Since we cannot deal with references to the session, write the whole - * store back. - * - * @param array $store. - * The content of the whole session data store, to replace all of the current data. - */ - protected function setStore($store) { - $session = $this->getSession(); - $session->set(static::SESSION_BASE_ATTRIBUTE, $store); - } - - /** - * Turn a path into the arrays we use internally. - * - * @param string $path - * Path into the store. - * @param bool $is_dir - * Path will be used as a container. Otherwise, just a scalar value. - * - * @return array|bool - * Return an array containing the "bottom" and "tip" of a directory - * hierarchy. You will want to save the 'bottom' array, but you may - * need to manipulate an object at the very tip of the hierarchy - * as defined in the path. The tip will be a string if we are scalar - * and an array otherwise. Since we don't want to create new - * sub arrays as a side effect, we return FALSE the intervening path - * does not exist. - */ - public function processPath($path, $is_dir = FALSE) { - // We need to create a reference into the store for the point - // the of the path, so get a copy of the store. - $store = $this->getStore(); - - if (empty($path)) { - return ['store' => &$store, 'tip' => &$store]; - } - $hierarchy = explode('/', $path); - if (empty($hierarchy) or empty($hierarchy[0])) { - return ['store' => &$store, 'tip' => &$store]; - } - $bottom =& $store; - $tip = array_pop($hierarchy); - - foreach ($hierarchy as $dir) { - if (!isset($bottom[$dir])) { - // If the path does not exist, DO NOT create it. - // That is handled by the stream wrapper code. - return FALSE; - } - $new_tip =& $bottom[$dir]; - $bottom =& $new_tip; - } - // If the hierarchy was empty, just point to the object. - $new_tip =& $bottom[$tip]; - $bottom =& $new_tip; - return ['store' => &$store, 'tip' => &$bottom]; - } - - /** - * The equivalent to dirname() and basename() for a path. - * - * @param string $path - * - * @return array - * . - */ - public function getParentPath($path) { - $dirs = explode('/', $path); - $tip = array_pop($dirs); - $parent = implode('/', $dirs); - return ['dirname' => $parent, 'basename' => $tip]; - } - - /** - * Clear a path into our store. - * - * @param string $path - * The path portion of a URI (i.e., without the SCHEME://). - */ - public function clearPath($path) { - $store = $this->getStore(); - if ($this->checkPath($path)) { - $path_info = $this->getParentPath($path); - $store_info = $this->processPath($path_info['dirname']); - if ($store_info === FALSE) { - // The path was not found, nothing to do. - return; - - } - // We want to clear the key at the tip, so... - unset($store_info['tip'][$path_info['basename']]); - // Write back to the store. - $this->setStore($store_info['store']); - } - - } - - /** - * Get a path. - * - * @param string $path - * A URI with the SCHEME:// part removed. - * - * @return mixed - * Return the stored value at this "node" of the store. - */ - public function getPath($path) { - $path_info = $this->getParentPath($path); - $store_info = $this->processPath(($path_info['dirname'])); - $leaf = $path_info['basename']; - if ($store_info === FALSE) { - return NULL; - } - if ($store_info['store'] === $store_info['tip']) { - // We are at the top of the hierarchy; return the store itself. - if (empty($path_info['basename'])) { - return $store_info['store']; - } - if (!isset($store_info['store'][$leaf])) { - return NULL; - } - } - return $store_info['tip'][$leaf]; - } - - /** - * Set a path. - * - * @param string $path - * Path into the store. - * @param string|array $value - * Set a value. - */ - public function setPath($path, $value) { - $path_info = $this->getParentPath($path); - $store_info = $this->processPath(($path_info['dirname'])); - if ($store_info !== FALSE) { - $store_info['tip'][$path_info['basename']] = $value; - } - $this->setStore($store_info['store']); - } - - /** - * Does path exist? - * - * @param string $path - * Path into the store. - */ - public function checkPath($path) { - $path_info = $this->getParentPath($path); - $store_info = $this->processPath($path_info['dirname']); - if (empty($store_info)) { - // Containing directory did not exist. - return FALSE; - } - // Check if we are at the root of a directory. - if ($path_info['basename'] === '') { - return TRUE; - } - return isset($store_info['tip'][$path_info['basename']]); - } - - /** - * Set up the store for use. - */ - public function setUpStore() { - // Nothing to do with $_SESSION version. - } - - - /** - * Zero out the store. - */ - public function cleanUpStore() { - $session = $this->getSession(); - $session->remove(static::SESSION_BASE_ATTRIBUTE); - } - -} diff --git a/stream_wrapper_example/stream_wrapper_example.info.yml b/stream_wrapper_example/stream_wrapper_example.info.yml deleted file mode 100644 index 29e3c37..0000000 --- a/stream_wrapper_example/stream_wrapper_example.info.yml +++ /dev/null @@ -1,7 +0,0 @@ -name: Stream Wrapper example -type: module -description: Example of implementing Stream Wrappers in Drupal. -package: Example modules -core: 8.x -dependencies: - - examples diff --git a/stream_wrapper_example/stream_wrapper_example.links.menu.yml b/stream_wrapper_example/stream_wrapper_example.links.menu.yml deleted file mode 100644 index 47fdf2b..0000000 --- a/stream_wrapper_example/stream_wrapper_example.links.menu.yml +++ /dev/null @@ -1,4 +0,0 @@ -# Menu links for the "Tools" menu. -stream_wrapper_example.description: - title: Stream Wrapper Example - route_name: stream_wrapper_example.description diff --git a/stream_wrapper_example/stream_wrapper_example.module b/stream_wrapper_example/stream_wrapper_example.module deleted file mode 100644 index eaa941f..0000000 --- a/stream_wrapper_example/stream_wrapper_example.module +++ /dev/null @@ -1,104 +0,0 @@ - [ - 'template' => 'description', - 'variables' => [ - 'admin_link' => NULL, - ], - ], - ]; -} diff --git a/stream_wrapper_example/stream_wrapper_example.routing.yml b/stream_wrapper_example/stream_wrapper_example.routing.yml deleted file mode 100644 index b76c8c0..0000000 --- a/stream_wrapper_example/stream_wrapper_example.routing.yml +++ /dev/null @@ -1,51 +0,0 @@ -# In order to view files created with our demo stream wrapper class, -# we need to use hook_file_download to grant any access. This route -# will make sure that we have an external URL for these files, and that -# our hook is called. -# -# In our implementation, access to the files is actually managed by -# permissions defined in file_example.permissions.yml. Since we also want our -# URLs to be served similar to how private: and temporary: URI are served by -# core, we also need to modify how the routing system handles the tail portion -# of the URL. Unlike Drupal 7, Drupal 8 does not ordinarily allow a "menu tail"; -# URLs need to be of a definite length or the router will not process them. To -# get around this, we also implement a "path processor", which we define as a -# service in our services file. Our path processor will do the extra steps needed -# to process our session file URLs. -# -# @see stream_wrapper_example.services.yml -# @see file_example_file_download() -# -stream_wrapper_example.files: - path: '/examples/stream_wrapper_example/files/{scheme}' - defaults: - _controller: 'Drupal\system\FileDownloadController::download' - scheme: session - requirements: - _access: 'TRUE' - -# In addition to the stream_wrapper_example.files route, which is actually matched by the router, -# we also need a route defintion to make our URLs. This is never referenced by the -# routing system, but is used by our stream wrapper class to create external URLs. -# -# @see FileExampleSessionStreamWrapper::getExternalUrl() -# -stream_wrapper_example.files.session: - path: '/examples/stream_wrapper_example/files/{filepath}' - defaults: - _controller: '\Drupal\system\FileDownloadController::download' - scheme: session - requirements: - # Permissive regex to allow slashes in filepath see - # http://symfony.com/doc/current/cookbook/routing/slash_in_parameter.html - filepath: .+ - _access: 'TRUE' - -# Finally, our controller class. -stream_wrapper_example.description: - path: '/examples/stream_wrapper_example' - defaults: - _controller: '\Drupal\stream_wrapper_example\Controller\ExampleController::description' - _title: 'Stream Wrapper Example' - requirements: - _permission: 'access content' diff --git a/stream_wrapper_example/stream_wrapper_example.services.yml b/stream_wrapper_example/stream_wrapper_example.services.yml deleted file mode 100644 index b6b2db3..0000000 --- a/stream_wrapper_example/stream_wrapper_example.services.yml +++ /dev/null @@ -1,34 +0,0 @@ -# -# As part of our demo, we implement a simple "file system" that lets us read and write -# files out of the $_SESSION. This isn't very practical, but it's a simple way to -# demonstrate what you can do with PHP's stream wrappers. -# -# To get a stream wrapper to work to define a stream wrapper class, we need to register -# that with the system. We can either do this manually by calling up the 'stream_wrapper.manager' -# service, but the better way to do this is to have the system autoload it by tagging the service, -# as we do here. -# -# We also want to securely serve up our fake session files. We'd like to use the same nice -# file paths that Core uses for private files. Since Drupal 8 no longer allows us to have -# "menu tails" (i.e., extra/parts/of/the/path after the default part of the path), we need -# to get some router superpowers. Our route (in stream_wrapper_example.routing.yml) will "gather up" -# the path with with a regular expression. But we need to do a little more that that. We -# also need to convince the routing system to see our weird, extra long route route. We -# do that using a "Path Processor". We register the path_process.sessions service with special -# tags to get it loaded for when the Drupal's routing system decides which path should get -# used. -# -# @see src/StreamWrapper/FileExampleSessionStreamWrapper.php -# @see src/PathProcessor/PathProcessorSessions.php -# @see stream_wrapper_example.routing.yml -# -services: - stream_wrapper_example.stream_wrapper: - class: Drupal\stream_wrapper_example\StreamWrapper\FileExampleSessionStreamWrapper - tags: - - { name: stream_wrapper, scheme: session } - - path_processor.sessions: - class: Drupal\stream_wrapper_example\PathProcessor\PathProcessorSessions - tags: - - { name: path_processor_inbound, priority: 200 } diff --git a/stream_wrapper_example/templates/description.html.twig b/stream_wrapper_example/templates/description.html.twig deleted file mode 100644 index bd780c1..0000000 --- a/stream_wrapper_example/templates/description.html.twig +++ /dev/null @@ -1,44 +0,0 @@ -{# -/** - * @file - * Contains the description text of an Example explanation/description page - * - * Available variables: - * - admin_link: The translated link pointing to a configuration page for the example. - */ -#} - -
The Stream Wrapper Example module demonstrates a PHP stream wrapper implementation.
- A stream wrapper is a class that implements something that looks and behaves like a
- file system. A particular implementation of a stream wrapper is called a scheme.
- Drupal 8 supports public, private, and temporary wrapper schemes. For example, you
- access a file in your public uploads directory via a "public" file URI such as
- public://images/big-logo.png. When you read, write, delete or move that
- file, the public scheme's stream wrapper class
- (\Drupal\Core\StreamWrapper\PublicStream) is invoked to do the reading,
- writing, deletion or moving. PHP does this automatically for you, creating the wrapper
- whenever some file operation needs to get done on a public:// file.
-
To demonstrate how to implement a stream wrapper, this example module creates a
- session wrapper scheme. It uses your session data (created when you
- log into Drupal) to create a nested array where the arrays represent directories,
- and scalar values represent files. This is completely impractical, and frankly,
- not terribly secure, so you should never enable this module on any site that's
- open to the Internet. But without using any special libraries, our stream wrapper
- class is able to create and delete directories, and read and write files.
-
If you want to play with session file URIs, we recommend also enabling
- the File Example (file_example.module), which will let you do the same things with
- the "session" scheme that you can do with public, private or temporary files.
A longer description of what code is where can be found in
- stream_wrapper_example.module. Definitely look through the code to see
- various implementation details.