public SocketStream(Context ctx, Socket socket, string openedPath, StreamContext context, bool isAsync = false) : base(ctx, null, StreamAccessOptions.Read | StreamAccessOptions.Write, openedPath, context) { Debug.Assert(socket != null); this.socket = socket; this.IsWriteBuffered = false; this.eof = false; this.isAsync = isAsync; this.IsReadBuffered = false; }
/// <summary> /// Tests whether a given interface is defined. /// </summary> /// <param name="ctx">Current runtime context.</param> /// <param name="ifaceName">The name of the interface.</param> /// <param name="autoload">Whether to attempt to call <c>__autoload</c>.</param> /// <returns><B>true</B> if the interface given by <paramref name="ifaceName"/> has been defined, /// <B>false</B> otherwise.</returns> public static bool interface_exists(Context ctx, string ifaceName, bool autoload = true) { var info = ctx.GetDeclaredType(ifaceName); if (info == null && autoload) { throw new NotImplementedException("autoload"); } // return info != null && info.Type.GetTypeInfo().IsInterface; }
/// <summary> /// Tests whether a given class is defined. /// </summary> /// <param name="ctx">Current runtime context.</param> /// <param name="className">The name of the class.</param> /// <param name="autoload">Whether to attempt to call <c>__autoload</c>.</param> /// <returns><B>true</B> if the class given by <paramref name="className"/> has been defined, /// <B>false</B> otherwise.</returns> public static bool class_exists(Context ctx, string className, bool autoload = true) { var info = ctx.GetDeclaredType(className); if (info == null && autoload) { throw new NotImplementedException("autoload"); } // return info != null; }
/// <summary> /// Calls a function or a method defined by callback with given arguments. /// </summary> /// <param name="ctx">Current runtime context.</param> /// <param name="function">Target callback.</param> /// <param name="args">The arguments.</param> /// <returns>The return value.</returns> public static PhpValue call_user_func(Context ctx, IPhpCallable function, params PhpValue[] args) { if (function == null) { //PhpException.ArgumentNull("function"); //return null; throw new ArgumentNullException(); // NOTE: should not be reached, runtime converts NULL to InvalidCallback instance } Debug.Assert(args != null); // invoke the callback: return function.Invoke(ctx, args); }
/// <summary> /// Calls a function or a method defined by callback with arguments stored in an array. /// </summary> /// <param name="ctx">Current runtime context.</param> /// <param name="function">Target callback.</param> /// <param name="args">Arguments. Can be null.</param> /// <returns>The returned value.</returns> public static PhpValue call_user_func_array(Context ctx, IPhpCallable function, PhpArray args) { PhpValue[] args_array; if (args != null && args.Count != 0) { args_array = new PhpValue[args.Count]; args.CopyValuesTo(args_array, 0); } else { args_array = Core.Utilities.ArrayUtils.EmptyValues; } return call_user_func(ctx, function, args_array); }
public static TextElement FromValue(Context ctx, PhpValue value) { switch (value.TypeCode) { case PhpTypeCode.Object: if (value.Object is byte[]) { return new TextElement((byte[])value.Object); } goto default; case PhpTypeCode.WritableString: return new TextElement(value.WritableString, ctx.StringEncoding); default: return new TextElement(value.ToStringOrThrow(ctx)); } }
/// <summary> /// Retrieves defined constants. /// </summary> /// <param name="ctx">Current runtime context.</param> /// <param name="categorize">Returns a multi-dimensional array with categories in the keys of the first dimension and constants and their values in the second dimension. </param> /// <returns>Retrives the names and values of all the constants currently defined.</returns> public static PhpArray get_defined_constants(Context ctx, bool categorize = false) { var result = new PhpArray(); if (categorize) { throw new NotImplementedException(); } else { foreach (var c in ctx.GetConstants()) { result.Add(c.Key, c.Value); } } // return result; }
int ProcessStatus(Context ctx, ref PhpValue status) { switch (status.TypeCode) { case PhpTypeCode.Alias: return ProcessStatus(ctx, ref status.Alias.Value); case PhpTypeCode.Long: case PhpTypeCode.Int32: return (int)status.ToLong(); default: if (ctx != null) { ctx.Echo(status); } return 0; } }
/// <summary> /// Increases the level of buffering, enables output buffering if disabled and assignes the filtering callback /// to the new level of buffering. /// </summary> /// <param name="ctx">Current runtime context.</param> /// <param name="filter">The filtering callback. Ignores invalid callbacks.</param> /// <param name="chunkSize">Not supported.</param> /// <param name="erase">Not supported.</param> /// <returns>Whether the filter is valid callback.</returns> public static bool ob_start(Context ctx, Delegate filter = null, int chunkSize = 0, bool erase = true) { if (chunkSize != 0) //PhpException.ArgumentValueNotSupported("chunkSize", "!= 0"); throw new NotSupportedException("chunkSize != 0"); if (!erase) //PhpException.ArgumentValueNotSupported("erase", erase); throw new NotSupportedException("erase == false"); ctx.BufferedOutput.IncreaseLevel(); bool result = true; // skips filter setting if filter is not specified or valid: if (filter != null) // && (result = filter.Bind())) // TODO: PhpCallback.Bind -> Delegate, done by caller ctx.BufferedOutput.SetFilter(filter); ctx.IsOutputBuffered = true; return result; }
public static int preg_match_all(Context ctx, string pattern, string subject) { PhpArray matches; return preg_match_all(ctx, pattern, subject, out matches); }
/// <summary> /// Create <see cref="Generator"/> with specified state machine function and parameters. /// </summary> public static Generator BuildGenerator(Context ctx, object @this, PhpArray locals, GeneratorStateMachineDelegate method) => new Generator(ctx, @this, locals, method);
/// <summary> /// Check if the path lays inside of the directory tree specified /// by the <c>open_basedir</c> configuration option and return the resulting <paramref name="absolutePath"/>. /// </summary> /// <param name="ctx">Current runtime context.</param> /// <param name="relativePath">The filename to search for.</param> /// <param name="absolutePath">The combined absolute path (either in the working directory /// or in an include path wherever it has been found first).</param> /// <returns><c>true</c> if the file was found in an include path.</returns> private static bool CheckIncludePath(Context ctx, string relativePath, ref string absolutePath) { // Note: If the absolutePath exists, it overtakse the include_path search. if (Path.IsPathRooted(relativePath)) return false; if (File.Exists(absolutePath)) return false; var paths = ctx.IncludePaths; if (paths == null || paths.Length == 0) return false; foreach (string s in paths) { if (string.IsNullOrEmpty(s)) continue; string abs = Path.GetFullPath(Path.Combine(s, relativePath)); if (File.Exists(abs)) { absolutePath = abs; return true; } } return false; }
/// <summary> /// Openes a PhpStream using the appropriate StreamWrapper. /// </summary> /// <param name="ctx">Current runtime context.</param> /// <param name="path">URI or filename of the resource to be opened.</param> /// <param name="mode">A file-access mode as passed to the PHP function.</param> /// <param name="options">A combination of <see cref="StreamOpenOptions"/>.</param> /// <param name="context">A valid StreamContext. Must not be <c>null</c>.</param> /// <returns></returns> public static PhpStream Open(Context ctx, string path, string mode, StreamOpenOptions options, StreamContext context) { if (context == null) throw new ArgumentNullException("context"); Debug.Assert(ctx != null); StreamWrapper wrapper; if (!PhpStream.ResolvePath(ctx, ref path, out wrapper, CheckAccessMode.FileMayExist, (CheckAccessOptions)options)) return null; return wrapper.Open(ctx, ref path, mode, options, context); }
/// <summary> /// Simple version of the stream opening function /// </summary> /// <param name="ctx">Current runtime context.</param> /// <param name="path">URI or filename of the resource to be opened</param> /// <param name="mode">File access mode</param> /// <returns></returns> internal static PhpStream Open(Context ctx, string path, StreamOpenMode mode) { string modeStr = null; switch (mode) { case StreamOpenMode.ReadBinary: modeStr = "rb"; break; case StreamOpenMode.WriteBinary: modeStr = "wb"; break; case StreamOpenMode.ReadText: modeStr = "rt"; break; case StreamOpenMode.WriteText: modeStr = "wt"; break; } Debug.Assert(modeStr != null); return Open(ctx, path, modeStr, StreamOpenOptions.Empty, StreamContext.Default); }
static void OutputChunks(Context ctx, object[] chunks, int count) { for (int i = 0; i < count; i++) { OutputChunk(ctx, chunks[i]); } }
internal void Output(Context ctx) { var chunks = _chunks; if (chunks != null) { if (chunks.GetType() == typeof(object[])) { OutputChunks(ctx, (object[])chunks, _chunksCount); } else { OutputChunk(ctx, chunks); } } }
public static int preg_match(Context ctx, string pattern, string subject, out PhpArray matches, int flags = 0, long offset = 0) { throw new NotImplementedException(); }
public static int preg_match_all(Context ctx, string pattern, string subject, out PhpArray matches, int flags = PREG_PATTERN_ORDER, int offset = 0) { throw new NotImplementedException(); }
public static int preg_match(Context ctx, string pattern, string subject) { var regex = new PerlRegex.Regex(pattern); return regex.Match(subject).Success ? 1 : 0; }
public static PhpValue date_sunset(Context ctx, int timestamp, TimeFormats format, double latitude, double longitude) { return GetSunTime(ctx, timestamp, format, latitude, longitude, Double.NaN, Double.NaN, false); }
public static PhpArray preg_grep(Context ctx, string pattern, PhpArray input, int flags = 0) { if (input == null) { return null; } var result = new PhpArray(input.Count); if (input.Count != 0) { var regex = new PerlRegex.Regex(pattern); var enumerator = input.GetFastEnumerator(); while (enumerator.MoveNext()) { var str = enumerator.CurrentValue.ToStringOrThrow(ctx); var m = regex.Match(str); // move a copy to return array if success and not invert or // not success and invert if (m.Success ^ (flags & PREG_GREP_INVERT) != 0) { result.Add(enumerator.CurrentKey, enumerator.CurrentValue.DeepCopy()); } } } // return result; }
public static PhpValue date_sunset(Context ctx, int timestamp, TimeFormats format, double latitude, double longitude, double zenith, double offset) { return GetSunTime(ctx, timestamp, format, latitude, longitude, zenith, offset, false); }
static void OutputChunk(Context ctx, object chunk) { AssertChunkObject(chunk); if (chunk.GetType() == typeof(string)) ctx.Output.Write((string)chunk); else if (chunk.GetType() == typeof(byte[])) ctx.OutputStream.Write((byte[])chunk); else if (chunk.GetType() == typeof(PhpString)) ((PhpString)chunk).Output(ctx); else if (chunk.GetType() == typeof(char[])) ctx.Output.Write((char[])chunk); else throw new ArgumentException(); }
static PhpValue GetSunTime(Context ctx, int timestamp, TimeFormats format, double latitude, double longitude, double zenith, double offset, bool getSunrise) { var zone = PhpTimeZone.GetCurrentTimeZone(ctx); var utc = DateTimeUtils.UnixTimeStampToUtc(timestamp); var local = TimeZoneInfo.ConvertTime(utc, zone); if (Double.IsNaN(latitude) || Double.IsNaN(longitude) || Double.IsNaN(zenith)) { //LibraryConfiguration config = LibraryConfiguration.GetLocal(ScriptContext.CurrentContext); //if (Double.IsNaN(latitude)) // latitude = config.Date.Latitude; //if (Double.IsNaN(longitude)) // longitude = config.Date.Longitude; //if (Double.IsNaN(zenith)) // zenith = (getSunrise) ? config.Date.SunriseZenith : config.Date.SunsetZenith; throw new NotImplementedException(); } if (Double.IsNaN(offset)) offset = zone.GetUtcOffset(local).TotalHours; double result_utc = CalculateSunTime(local.DayOfYear, latitude, longitude, zenith, getSunrise); double result = result_utc + offset; switch (format) { case TimeFormats.Integer: return PhpValue.Create((timestamp - (timestamp % (24 * 3600))) + (int)(3600 * result)); case TimeFormats.String: return PhpValue.Create(string.Format("{0:00}:{1:00}", (int)result, (int)(60 * (result - (double)(int)result)))); case TimeFormats.Double: return PhpValue.Create(result); default: //PhpException.InvalidArgument("format"); //return PhpValue.Null; throw new ArgumentException(); } }
public string ToStringOrThrow(Context ctx) => ToString(ctx.StringEncoding);
public static PhpValue preg_replace(Context ctx, PhpValue pattern, PhpValue replacement, PhpValue subject, int limit = -1) { long count; return preg_replace(ctx, pattern, replacement, subject, limit, out count); }
public static PhpStream Open(Context ctx, string path, string mode, StreamOpenOptions options) { return Open(ctx, path, mode, options, StreamContext.Default); }
/// <summary> /// Perform a regular expression search and replace. /// </summary> /// <param name="ctx">A reference to current context. Cannot be <c>null</c>.</param> /// <param name="pattern">The pattern to search for. It can be either a string or an array with strings.</param> /// <param name="replacement">The string or an array with strings to replace. /// If this parameter is a string and the pattern parameter is an array, all patterns will be /// replaced by that string. If both pattern and replacement parameters are arrays, each pattern will be /// replaced by the replacement counterpart. If there are fewer elements in the replacement array than /// in the pattern array, any extra patterns will be replaced by an empty string.</param> /// <param name="subject">The string or an array with strings to search and replace. /// If subject is an array, then the search and replace is performed on every entry of subject, and the return value is an array as well.</param> /// <param name="limit">The maximum possible replacements for each pattern in each subject string. Defaults to <c>-1</c> (no limit).</param> /// <param name="count">This variable will be filled with the number of replacements done.</param> /// <returns></returns> public static PhpValue preg_replace(Context ctx, PhpValue pattern, PhpValue replacement, PhpValue subject, int limit, out long count) { count = 0; // PHP's behaviour for undocumented limit range if (limit < -1) { limit = 0; } // var replacement_array = replacement.AsArray(); var pattern_array = pattern.AsArray(); if (pattern_array == null) { if (replacement_array == null) { // string pattern // string replacement return preg_replace(ctx, pattern.ToStringOrThrow(ctx), replacement.ToStringOrThrow(ctx), null, subject, limit, ref count); } else { // string pattern and array replacement not allowed: throw new ArgumentException("replacement_array_pattern_not", nameof(replacement)); // return PhpValue.Null; } } else if (replacement_array == null) { // array pattern // string replacement } else { // array pattern // array replacement } throw new NotImplementedException(); }
/// <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; }
static PhpValue preg_replace(Context ctx, string pattern, string replacement, PhpCallable callback, PhpValue subject, int limit, ref long count) { var regex = new PerlRegex.Regex(pattern); // TODO: count // TODO: callback var subject_array = subject.AsArray(); if (subject_array == null) { return PhpValue.Create(regex.Replace(subject.ToStringOrThrow(ctx), replacement, limit)); } else { var arr = new PhpArray(subject_array, false); var enumerator = arr.GetFastEnumerator(); while (enumerator.MoveNext()) { var newvalue = regex.Replace(enumerator.CurrentValue.ToStringOrThrow(ctx), replacement, limit); enumerator.CurrentValue = PhpValue.Create(newvalue); } return PhpValue.Create(arr); } }
/// <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; }
string IPhpConvertible.ToStringOrThrow(Context ctx) => ToString();