Abstract base class for PHP stream wrappers. Descendants define methods implementing fopen, stat, unlink, rename, opendir, mkdir and rmdir for different stream types.
Each script has its own copy of registeredWrappers stored in the context.

PhpStream is created by a StreamWrapper on a call to fopen(). Wrappers are stateless: they provide an instance of PhpStream on fopen() and an instance of DirectoryListing on opendir().

Наследование: IDisposable
Пример #1
0
        /// <summary>
        /// PhpStream is created by a StreamWrapper together with the
        /// encapsulated RawStream (the actual file opening is handled 
        /// by the wrapper).
        /// </summary>
        /// <remarks>
        /// This class newly implements the auto-remove behavior too
        /// (see <see cref="StreamAccessOptions.Temporary"/>).
        /// </remarks>
        /// <param name="ctx">Runtime context.</param>
        /// <param name="openingWrapper">The parent instance.</param>
        /// <param name="accessOptions">The additional options parsed from the <c>fopen()</c> mode.</param>
        /// <param name="openedPath">The absolute path to the opened resource.</param>
        /// <param name="context">The stream context passed to fopen().</param>
        public PhpStream(Context ctx, StreamWrapper openingWrapper, StreamAccessOptions accessOptions, string openedPath, StreamContext context)
            : base(PhpStreamTypeName)
        {
            Debug.Assert(ctx != null);
            Debug.Assert(context != null);

            _ctx = ctx;
            _context = context;

            this.Wrapper = openingWrapper;
            this.OpenedPath = openedPath;

            // Stream modifiers (defined in open-time).
            this.Options = accessOptions;

            // Allocate the text conversion filters for this stream.
            if ((accessOptions & StreamAccessOptions.UseText) > 0)
            {
                if ((accessOptions & StreamAccessOptions.Read) > 0)
                {
                    textReadFilter = new TextReadFilter();
                }
                if ((accessOptions & StreamAccessOptions.Write) > 0)
                {
                    textWriteFilter = new TextWriteFilter();
                }
            }

            // this.readTimeout = ScriptContext.CurrentContext.Config.FileSystem.DefaultSocketTimeout;
        }
Пример #2
0
        /// <summary>
        /// Merges the path with the current working directory
        /// to get a canonicalized absolute pathname representing the same file.
        /// </summary>
        /// <remarks>
        /// This method is an analogy of <c>main/safe_mode.c: php_checkuid</c>.
        /// Looks for the file in the <c>include_path</c> and checks for <c>open_basedir</c> restrictions.
        /// </remarks>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="path">An absolute or relative path to a file.</param>
        /// <param name="wrapper">The wrapper found for the specified file or <c>null</c> if the path resolution fails.</param>
        /// <param name="mode">The checking mode of the <see cref="CheckAccess"/> method (file, directory etc.).</param>
        /// <param name="options">Additional options for the <see cref="CheckAccess"/> method.</param>
        /// <returns><c>true</c> if all the resolution and checking passed without an error, <b>false</b> otherwise.</returns>
        /// <exception cref="PhpException">Security violation - when the target file 
        /// lays outside the tree defined by <c>open_basedir</c> configuration option.</exception>
        public static bool ResolvePath(Context ctx, ref string path, out StreamWrapper wrapper, CheckAccessMode mode, CheckAccessOptions options)
        {
            // Path will contain the absolute path without file:// or the complete URL; filename is the relative path.
            string filename, scheme = GetSchemeInternal(path, out filename);
            wrapper = StreamWrapper.GetWrapper(ctx, scheme, (StreamOptions)options);
            if (wrapper == null) return false;

            if (wrapper.IsUrl)
            {
                // Note: path contains the whole URL, filename the same without the scheme:// portion.
                // What to check more?
            }
            else if (scheme != "php")
            {
                try
                {
                    // Filename contains the original path without the scheme:// portion, check for include path.
                    bool isInclude = false;
                    if ((options & CheckAccessOptions.UseIncludePath) > 0)
                    {
                        isInclude = CheckIncludePath(ctx, filename, ref path);
                    }

                    // Path will now contain an absolute path (either to an include or actual directory).
                    if (!isInclude)
                    {
                        path = Path.GetFullPath(Path.Combine(ctx.WorkingDirectory, filename));
                    }
                }
                catch (System.Exception)
                {
                    if ((options & CheckAccessOptions.Quiet) == 0)
                        PhpException.Throw(PhpError.Warning, ErrResources.stream_filename_invalid, FileSystemUtils.StripPassword(path));
                    return false;
                }

                // NOTE: we should let OS & Security configuration to decide
                //var global_config = Configuration.Global;

                //// Note: extensions check open_basedir too -> double check..
                //if (!global_config.SafeMode.IsPathAllowed(path))
                //{
                //    if ((options & CheckAccessOptions.Quiet) == 0)
                //        PhpException.Throw(PhpError.Warning, ErrResources.open_basedir_effect, path, global_config.SafeMode.GetAllowedPathPrefixesJoin());
                //    return false;
                //}

                // Replace all '/' with '\'.
                // path = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
                Debug.Assert(
                    path.IndexOf(Path.AltDirectorySeparatorChar) == -1 ||
                    (Path.AltDirectorySeparatorChar == Path.DirectorySeparatorChar),    // on Mono, so ignore it
                    string.Format("'{0}' should not contain '{1}' char.", path, Path.AltDirectorySeparatorChar));

                // The file wrapper expects an absolute path w/o the scheme, others expect the scheme://url.
                if (scheme != "file")
                {
                    path = String.Format("{0}://{1}", scheme, path);
                }
            }

            return true;
        }
Пример #3
0
 public NativeStream(Context ctx, Stream nativeStream, StreamWrapper openingWrapper, StreamAccessOptions accessOptions, string openedPath, StreamContext context)
     : base(ctx, openingWrapper, accessOptions, openedPath, context)
 {
     Debug.Assert(nativeStream != null);
     this.stream = nativeStream;
 }
Пример #4
0
 public NativeStream(Context ctx, Stream nativeStream, StreamWrapper openingWrapper, StreamAccessOptions accessOptions, string openedPath, StreamContext context)
     : base(ctx, openingWrapper, accessOptions, openedPath, context)
 {
     Debug.Assert(nativeStream != null);
     this.stream = nativeStream;
 }
Пример #5
0
        ///// <summary>
        ///// Insert a new wrapper to the list of user StreamWrappers.
        ///// </summary>
        ///// <remarks>
        ///// Each script has its own set of user StreamWrappers registered
        ///// by stream_wrapper_register() stored in the ScriptContext.
        ///// </remarks>
        ///// <param name="protocol">The scheme portion of URLs this wrapper can handle.</param>
        ///// <param name="wrapper">An instance of the corresponding StreamWrapper descendant.</param>
        ///// <returns>True if succeeds, false if the scheme is already registered.</returns>
        //public static bool RegisterUserWrapper(string protocol, StreamWrapper wrapper)
        //{
        //    // Userwrappers may be initialized to null
        //    if (UserWrappers == null)
        //        CreateUserWrapperTable();

        //    UserWrappers.Add(protocol, wrapper);
        //    return true;
        //}

        /// <summary>
        /// Register a new system wrapper
        /// </summary>
        /// <param name="wrapper">An instance of the corresponding StreamWrapper descendant.</param>
        /// <returns>True if succeeds, false if the scheme is already registered.</returns>
        public static bool RegisterSystemWrapper(StreamWrapper wrapper)
        {
            if (!systemStreamWrappers.ContainsKey(wrapper.Scheme))
            {
                systemStreamWrappers.Add(wrapper.Scheme, wrapper);
                return true;
            }
            return false;
        }
Пример #6
0
 public NativeStream(IEncodingProvider enc_provider, Stream nativeStream, StreamWrapper openingWrapper, StreamAccessOptions accessOptions, string openedPath, StreamContext context)
     : base(enc_provider, openingWrapper, accessOptions, openedPath, context)
 {
     Debug.Assert(nativeStream != null);
     this.stream = nativeStream;
 }