diff -r 07239de796bb -r e756a8c72c3d cms/drupal/includes/stream_wrappers.inc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cms/drupal/includes/stream_wrappers.inc Fri Sep 08 12:04:06 2017 +0200 @@ -0,0 +1,982 @@ +uri = $uri; + } + + /** + * Base implementation of getUri(). + */ + function getUri() { + return $this->uri; + } + + /** + * Returns the local writable target of the resource within the stream. + * + * This function should be used in place of calls to realpath() or similar + * functions when attempting to determine the location of a file. While + * functions like realpath() may return the location of a read-only file, this + * method may return a URI or path suitable for writing that is completely + * separate from the URI used for reading. + * + * @param $uri + * Optional URI. + * + * @return + * Returns a string representing a location suitable for writing of a file, + * or FALSE if unable to write to the file such as with read-only streams. + */ + protected 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. + return trim($target, '\/'); + } + + /** + * Base implementation of getMimeType(). + */ + static function getMimeType($uri, $mapping = NULL) { + if (!isset($mapping)) { + // The default file map, defined in file.mimetypes.inc is quite big. + // We only load it when necessary. + include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc'; + $mapping = file_mimetype_mapping(); + } + + $extension = ''; + $file_parts = explode('.', drupal_basename($uri)); + + // Remove the first part: a full filename should not match an extension. + array_shift($file_parts); + + // Iterate over the file parts, trying to find a match. + // For my.awesome.image.jpeg, we try: + // - jpeg + // - image.jpeg, and + // - awesome.image.jpeg + while ($additional_part = array_pop($file_parts)) { + $extension = strtolower($additional_part . ($extension ? '.' . $extension : '')); + if (isset($mapping['extensions'][$extension])) { + return $mapping['mimetypes'][$mapping['extensions'][$extension]]; + } + } + + return 'application/octet-stream'; + } + + /** + * Base implementation of chmod(). + */ + function chmod($mode) { + $output = @chmod($this->getLocalPath(), $mode); + // We are modifying the underlying file here, so we have to clear the stat + // cache so that PHP understands that URI has changed too. + clearstatcache(); + return $output; + } + + /** + * Base implementation of realpath(). + */ + function realpath() { + return $this->getLocalPath(); + } + + /** + * Returns the canonical absolute path of the URI, if possible. + * + * @param string $uri + * (optional) The stream wrapper URI to be converted to a canonical + * absolute path. This may point to a directory or another type of file. + * + * @return string|false + * If $uri is not set, returns the canonical absolute path of the URI + * previously set by the DrupalStreamWrapperInterface::setUri() function. + * If $uri is set and valid for this class, returns its canonical absolute + * path, as determined by the realpath() function. If $uri is set but not + * valid, returns FALSE. + */ + protected function getLocalPath($uri = NULL) { + if (!isset($uri)) { + $uri = $this->uri; + } + $path = $this->getDirectoryPath() . '/' . $this->getTarget($uri); + $realpath = realpath($path); + if (!$realpath) { + // This file does not yet exist. + $realpath = realpath(dirname($path)) . '/' . drupal_basename($path); + } + $directory = realpath($this->getDirectoryPath()); + if (!$realpath || !$directory || strpos($realpath, $directory) !== 0) { + return FALSE; + } + return $realpath; + } + + /** + * Support for fopen(), file_get_contents(), file_put_contents() etc. + * + * @param $uri + * A string containing the URI to the file to open. + * @param $mode + * The file mode ("r", "wb" etc.). + * @param $options + * A bit mask of STREAM_USE_PATH and STREAM_REPORT_ERRORS. + * @param $opened_path + * A string containing the path actually opened. + * + * @return + * Returns TRUE if file was opened successfully. + * + * @see http://php.net/manual/streamwrapper.stream-open.php + */ + public function stream_open($uri, $mode, $options, &$opened_path) { + $this->uri = $uri; + $path = $this->getLocalPath(); + $this->handle = ($options & STREAM_REPORT_ERRORS) ? fopen($path, $mode) : @fopen($path, $mode); + + if ((bool) $this->handle && $options & STREAM_USE_PATH) { + $opened_path = $path; + } + + return (bool) $this->handle; + } + + /** + * Support for flock(). + * + * @param $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 + * Always returns TRUE at the present time. + * + * @see http://php.net/manual/streamwrapper.stream-lock.php + */ + public function stream_lock($operation) { + if (in_array($operation, array(LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB))) { + return flock($this->handle, $operation); + } + + return TRUE; + } + + /** + * Support for fread(), file_get_contents() etc. + * + * @param $count + * Maximum number of bytes to be read. + * + * @return + * The string that was read, or FALSE in case of an error. + * + * @see http://php.net/manual/streamwrapper.stream-read.php + */ + public function stream_read($count) { + return fread($this->handle, $count); + } + + /** + * Support for fwrite(), file_put_contents() etc. + * + * @param $data + * The string to be written. + * + * @return + * The number of bytes written (integer). + * + * @see http://php.net/manual/streamwrapper.stream-write.php + */ + public function stream_write($data) { + return fwrite($this->handle, $data); + } + + /** + * Support for feof(). + * + * @return + * TRUE if end-of-file has been reached. + * + * @see http://php.net/manual/streamwrapper.stream-eof.php + */ + public function stream_eof() { + return feof($this->handle); + } + + /** + * Support for fseek(). + * + * @param $offset + * The byte offset to got to. + * @param $whence + * SEEK_SET, SEEK_CUR, or SEEK_END. + * + * @return + * TRUE on success. + * + * @see http://php.net/manual/streamwrapper.stream-seek.php + */ + public function stream_seek($offset, $whence) { + // fseek returns 0 on success and -1 on a failure. + // stream_seek 1 on success and 0 on a failure. + return !fseek($this->handle, $offset, $whence); + } + + /** + * Support for fflush(). + * + * @return + * TRUE if data was successfully stored (or there was no data to store). + * + * @see http://php.net/manual/streamwrapper.stream-flush.php + */ + public function stream_flush() { + return fflush($this->handle); + } + + /** + * Support for ftell(). + * + * @return + * The current offset in bytes from the beginning of file. + * + * @see http://php.net/manual/streamwrapper.stream-tell.php + */ + public function stream_tell() { + return ftell($this->handle); + } + + /** + * Support for fstat(). + * + * @return + * 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/streamwrapper.stream-stat.php + */ + public function stream_stat() { + return fstat($this->handle); + } + + /** + * Support for fclose(). + * + * @return + * TRUE if stream was successfully closed. + * + * @see http://php.net/manual/streamwrapper.stream-close.php + */ + public function stream_close() { + return fclose($this->handle); + } + + /** + * Sets metadata on the stream. + * + * WARNING: Do not call this method directly! It will be called internally by + * PHP itself when one of the following functions is called on a stream URL: + * + * @param string $uri + * 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 touch() + * @see chmod() + * @see chown() + * @see chgrp() + * @link http://php.net/manual/streamwrapper.stream-metadata.php + */ + 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; + } + + /** + * Truncate stream. + * + * Will respond to truncation; e.g., through ftruncate(). + * + * @param int $new_size + * The new size. + * + * @return bool + * TRUE on success, FALSE otherwise. + */ + public function stream_truncate($new_size) { + return ftruncate($this->handle, $new_size); + } + + /** + * 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() + * @link http://php.net/manual/streamwrapper.stream-cast.php + */ + public function stream_cast($cast_as) { + return $this->handle ? $this->handle : FALSE; + } + + /** + * Change stream options. + * + * This method is called to set options on the stream. + * + * Since Windows systems do not allow it and it is not needed for most use + * cases anyway, this method is not supported on local files and will trigger + * an error and return false. If needed, custom subclasses can provide + * OS-specific implementations for advanced use cases. + * + * @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) { + trigger_error('stream_set_option() not supported for local file based stream wrappers', E_USER_WARNING); + return FALSE; + } + + /** + * Support for unlink(). + * + * @param $uri + * A string containing the URI to the resource to delete. + * + * @return + * TRUE if resource was successfully deleted. + * + * @see http://php.net/manual/streamwrapper.unlink.php + */ + public function unlink($uri) { + $this->uri = $uri; + return drupal_unlink($this->getLocalPath()); + } + + /** + * Support for rename(). + * + * @param $from_uri, + * The URI to the file to rename. + * @param $to_uri + * The new URI for file. + * + * @return + * TRUE if file was successfully renamed. + * + * @see http://php.net/manual/streamwrapper.rename.php + */ + public function rename($from_uri, $to_uri) { + return rename($this->getLocalPath($from_uri), $this->getLocalPath($to_uri)); + } + + /** + * Gets the name of the directory from a given path. + * + * This method is usually accessed through drupal_dirname(), which wraps + * around the PHP dirname() function because it does not support stream + * wrappers. + * + * @param $uri + * A URI or path. + * + * @return + * A string containing the directory name. + * + * @see drupal_dirname() + */ + public function dirname($uri = NULL) { + list($scheme, $target) = explode('://', $uri, 2); + $target = $this->getTarget($uri); + $dirname = dirname($target); + + if ($dirname == '.') { + $dirname = ''; + } + + return $scheme . '://' . $dirname; + } + + /** + * Support for mkdir(). + * + * @param $uri + * A string containing the URI to the directory to create. + * @param $mode + * Permission flags - see mkdir(). + * @param $options + * A bit mask of STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE. + * + * @return + * TRUE if directory was successfully created. + * + * @see http://php.net/manual/streamwrapper.mkdir.php + */ + public function mkdir($uri, $mode, $options) { + $this->uri = $uri; + $recursive = (bool) ($options & STREAM_MKDIR_RECURSIVE); + if ($recursive) { + // $this->getLocalPath() fails if $uri has multiple levels of directories + // that do not yet exist. + $localpath = $this->getDirectoryPath() . '/' . $this->getTarget($uri); + } + else { + $localpath = $this->getLocalPath($uri); + } + if ($options & STREAM_REPORT_ERRORS) { + return mkdir($localpath, $mode, $recursive); + } + else { + return @mkdir($localpath, $mode, $recursive); + } + } + + /** + * Support for rmdir(). + * + * @param $uri + * A string containing the URI to the directory to delete. + * @param $options + * A bit mask of STREAM_REPORT_ERRORS. + * + * @return + * TRUE if directory was successfully removed. + * + * @see http://php.net/manual/streamwrapper.rmdir.php + */ + public function rmdir($uri, $options) { + $this->uri = $uri; + if ($options & STREAM_REPORT_ERRORS) { + return drupal_rmdir($this->getLocalPath()); + } + else { + return @drupal_rmdir($this->getLocalPath()); + } + } + + /** + * Support for stat(). + * + * @param $uri + * A string containing the URI to get information about. + * @param $flags + * A bit mask of STREAM_URL_STAT_LINK and STREAM_URL_STAT_QUIET. + * + * @return + * 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/streamwrapper.url-stat.php + */ + public function url_stat($uri, $flags) { + $this->uri = $uri; + $path = $this->getLocalPath(); + // Suppress warnings if requested or if the file or directory does not + // exist. This is consistent with PHP's plain filesystem stream wrapper. + if ($flags & STREAM_URL_STAT_QUIET || !file_exists($path)) { + return @stat($path); + } + else { + return stat($path); + } + } + + /** + * Support for opendir(). + * + * @param $uri + * A string containing the URI to the directory to open. + * @param $options + * Unknown (parameter is not documented in PHP Manual). + * + * @return + * TRUE on success. + * + * @see http://php.net/manual/streamwrapper.dir-opendir.php + */ + public function dir_opendir($uri, $options) { + $this->uri = $uri; + $this->handle = opendir($this->getLocalPath()); + + return (bool) $this->handle; + } + + /** + * Support for readdir(). + * + * @return + * The next filename, or FALSE if there are no more files in the directory. + * + * @see http://php.net/manual/streamwrapper.dir-readdir.php + */ + public function dir_readdir() { + return readdir($this->handle); + } + + /** + * Support for rewinddir(). + * + * @return + * TRUE on success. + * + * @see http://php.net/manual/streamwrapper.dir-rewinddir.php + */ + public function dir_rewinddir() { + rewinddir($this->handle); + // We do not really have a way to signal a failure as rewinddir() does not + // have a return value and there is no way to read a directory handler + // without advancing to the next file. + return TRUE; + } + + /** + * Support for closedir(). + * + * @return + * TRUE on success. + * + * @see http://php.net/manual/streamwrapper.dir-closedir.php + */ + public function dir_closedir() { + closedir($this->handle); + // We do not really have a way to signal a failure as closedir() does not + // have a return value. + return TRUE; + } +} + +/** + * Drupal public (public://) stream wrapper class. + * + * Provides support for storing publicly accessible files with the Drupal file + * interface. + */ +class DrupalPublicStreamWrapper extends DrupalLocalStreamWrapper { + /** + * Implements abstract public function getDirectoryPath() + */ + public function getDirectoryPath() { + return variable_get('file_public_path', conf_path() . '/files'); + } + + /** + * Overrides getExternalUrl(). + * + * Return the HTML URI of a public file. + */ + function getExternalUrl() { + $path = str_replace('\\', '/', $this->getTarget()); + return $GLOBALS['base_url'] . '/' . self::getDirectoryPath() . '/' . drupal_encode_path($path); + } +} + + +/** + * Drupal private (private://) stream wrapper class. + * + * Provides support for storing privately accessible files with the Drupal file + * interface. + */ +class DrupalPrivateStreamWrapper extends DrupalLocalStreamWrapper { + /** + * Implements abstract public function getDirectoryPath() + */ + public function getDirectoryPath() { + return variable_get('file_private_path', ''); + } + + /** + * Overrides getExternalUrl(). + * + * Return the HTML URI of a private file. + */ + function getExternalUrl() { + $path = str_replace('\\', '/', $this->getTarget()); + return url('system/files/' . $path, array('absolute' => TRUE)); + } +} + +/** + * Drupal temporary (temporary://) stream wrapper class. + * + * Provides support for storing temporarily accessible files with the Drupal + * file interface. + * + * Extends DrupalPublicStreamWrapper. + */ +class DrupalTemporaryStreamWrapper extends DrupalLocalStreamWrapper { + /** + * Implements abstract public function getDirectoryPath() + */ + public function getDirectoryPath() { + return variable_get('file_temporary_path', file_directory_temp()); + } + + /** + * Overrides getExternalUrl(). + */ + public function getExternalUrl() { + $path = str_replace('\\', '/', $this->getTarget()); + return url('system/temporary/' . $path, array('absolute' => TRUE)); + } +}