diff --git a/Source/ClassLibrary/DateTime.CLR/DateTime.cs b/Source/ClassLibrary/DateTime.CLR/DateTime.cs
index 3028d6e2..788fa44c 100644
--- a/Source/ClassLibrary/DateTime.CLR/DateTime.cs
+++ b/Source/ClassLibrary/DateTime.CLR/DateTime.cs
@@ -611,7 +611,7 @@ public static string FormatDate(string format)
/// Nuber of seconds since 1970 specifying a date.
/// Formatted string.
[ImplementsFunction("date")]
- public static string FormatDate(string format, int timestamp)
+ public static string FormatDate(string format, long timestamp)
{
return FormatDate(format, DateTimeUtils.UnixTimeStampToUtc(timestamp), PhpTimeZone.CurrentTimeZone);
}
@@ -634,7 +634,7 @@ public static string FormatUtcDate(string format)
/// Nuber of seconds since 1970 specifying a date.
/// Formatted string.
[ImplementsFunction("gmdate")]
- public static string FormatUtcDate(string format, int timestamp)
+ public static string FormatUtcDate(string format, long timestamp)
{
return FormatDate(format, DateTimeUtils.UnixTimeStampToUtc(timestamp), DateTimeUtils.UtcTimeZone);
}
@@ -645,7 +645,7 @@ public static string FormatUtcDate(string format, int timestamp)
/// Format definition for output.
/// Part of the date, e.g. month or hours.
[ImplementsFunction("idate")]
- public static int GetDatePart(string format)
+ public static long GetDatePart(string format)
{
if (format == null || format.Length != 1)
PhpException.InvalidArgument("format");
@@ -660,7 +660,7 @@ public static int GetDatePart(string format)
/// Nuber of seconds since 1970 specifying a date.
/// Part of the date, e.g. month or hours.
[ImplementsFunction("idate")]
- public static int GetDatePart(string format, int timestamp)
+ public static long GetDatePart(string format, long timestamp)
{
if (format == null || format.Length != 1)
PhpException.InvalidArgument("format");
@@ -668,7 +668,7 @@ public static int GetDatePart(string format, int timestamp)
return GetDatePart(format[0], DateTimeUtils.UnixTimeStampToUtc(timestamp), PhpTimeZone.CurrentTimeZone);
}
- private static int GetDatePart(char format, DateTime utc, TimeZoneInfo/*!*/ zone)
+ private static long GetDatePart(char format, DateTime utc, TimeZoneInfo/*!*/ zone)
{
DateTime local = TimeZoneInfo.ConvertTimeFromUtc(utc, zone);// zone.ToLocalTime(utc);
@@ -1035,7 +1035,7 @@ private static void GetIsoWeekAndYear(DateTime dt, out int week, out int year)
private static int GetSwatchBeat(DateTime utc)
{
- int seconds = DateTimeUtils.UtcToUnixTimeStamp(utc);
+ long seconds = DateTimeUtils.UtcToUnixTimeStamp(utc);
int beat = (int)(((seconds - (seconds - ((seconds % 86400) + 3600))) * 10) / 864) % 1000;
return (beat < 0) ? beat + 1000 : beat;
}
@@ -1080,7 +1080,7 @@ public static string FormatTime(string format)
/// Number of seconds since 1970 representing the time to format.
/// Formatted string representing date and time.
[ImplementsFunction("strftime")]
- public static string FormatTime(string format, int timestamp)
+ public static string FormatTime(string format, long timestamp)
{
return FormatTime(format, DateTimeUtils.UnixTimeStampToUtc(timestamp), PhpTimeZone.CurrentTimeZone);
}
@@ -1103,7 +1103,7 @@ public static string FormatUtcTime(string format)
/// Number of seconds since 1970 representing the time to format.
/// Formatted string representing date and time.
[ImplementsFunction("gmstrftime")]
- public static string FormatUtcTime(string format, int timestamp)
+ public static string FormatUtcTime(string format, long timestamp)
{
return FormatTime(format, DateTimeUtils.UnixTimeStampToUtc(timestamp), DateTimeUtils.UtcTimeZone);
}
@@ -1349,56 +1349,56 @@ private static string FormatTime(string format, DateTime utc, TimeZoneInfo/*!*/
#region gmmktime
[ImplementsFunction("gmmktime")]
- public static int MakeUtcTime()
+ public static long MakeUtcTime()
{
DateTime utc_now = DateTime.UtcNow;
return MakeUtcTime(utc_now.Hour, utc_now.Minute, utc_now.Second, utc_now.Month, utc_now.Day, utc_now.Year);
}
[ImplementsFunction("gmmktime")]
- public static int MakeUtcTime(int hour)
+ public static long MakeUtcTime(int hour)
{
DateTime utc_now = DateTime.UtcNow;
return MakeUtcTime(hour, utc_now.Minute, utc_now.Second, utc_now.Month, utc_now.Day, utc_now.Year);
}
[ImplementsFunction("gmmktime")]
- public static int MakeUtcTime(int hour, int minute)
+ public static long MakeUtcTime(int hour, int minute)
{
DateTime utc_now = DateTime.UtcNow;
return MakeUtcTime(hour, minute, utc_now.Second, utc_now.Month, utc_now.Day, utc_now.Year);
}
[ImplementsFunction("gmmktime")]
- public static int MakeUtcTime(int hour, int minute, int second)
+ public static long MakeUtcTime(int hour, int minute, int second)
{
DateTime utc_now = DateTime.UtcNow;
return MakeUtcTime(hour, minute, second, utc_now.Month, utc_now.Day, utc_now.Year);
}
[ImplementsFunction("gmmktime")]
- public static int MakeUtcTime(int hour, int minute, int second, int month)
+ public static long MakeUtcTime(int hour, int minute, int second, int month)
{
DateTime utc_now = DateTime.UtcNow;
return MakeUtcTime(hour, minute, second, month, utc_now.Day, utc_now.Year);
}
[ImplementsFunction("gmmktime")]
- public static int MakeUtcTime(int hour, int minute, int second, int month, int day)
+ public static long MakeUtcTime(int hour, int minute, int second, int month, int day)
{
DateTime utc_now = DateTime.UtcNow;
return MakeUtcTime(hour, minute, second, month, day, utc_now.Year);
}
[ImplementsFunction("gmmktime")]
- public static int MakeUtcTime(int hour, int minute, int second, int month, int day, int year, int dummy)
+ public static long MakeUtcTime(int hour, int minute, int second, int month, int day, int year, int dummy)
{
// According to PHP manual daylight savings time parameter ignored
return MakeUtcTime(hour, minute, second, month, day, year);
}
[ImplementsFunction("gmmktime")]
- public static int MakeUtcTime(int hour, int minute, int second, int month, int day, int year)
+ public static long MakeUtcTime(int hour, int minute, int second, int month, int day, int year)
{
return DateTimeUtils.UtcToUnixTimeStamp(MakeDateTime(hour, minute, second, month, day, year));
}
@@ -1412,7 +1412,7 @@ public static int MakeUtcTime(int hour, int minute, int second, int month, int d
///
/// Unix timestamp.
[ImplementsFunction("mktime")]
- public static int MakeTime()
+ public static long MakeTime()
{
DateTime now = Now;
return MakeTime(now.Hour, now.Minute, now.Second, now.Month, now.Day, now.Year, -1);
@@ -1425,7 +1425,7 @@ public static int MakeTime()
/// The hour.
/// Unix timestamp.
[ImplementsFunction("mktime")]
- public static int MakeTime(int hour)
+ public static long MakeTime(int hour)
{
DateTime now = Now;
return MakeTime(hour, now.Minute, now.Second, now.Month, now.Day, now.Year, -1);
@@ -1439,7 +1439,7 @@ public static int MakeTime(int hour)
/// The minute.
/// Unix timestamp.
[ImplementsFunction("mktime")]
- public static int MakeTime(int hour, int minute)
+ public static long MakeTime(int hour, int minute)
{
DateTime now = Now;
return MakeTime(hour, minute, now.Second, now.Month, now.Day, now.Year, -1);
@@ -1454,7 +1454,7 @@ public static int MakeTime(int hour, int minute)
/// The second.
/// Unix timestamp.
[ImplementsFunction("mktime")]
- public static int MakeTime(int hour, int minute, int second)
+ public static long MakeTime(int hour, int minute, int second)
{
DateTime now = Now;
return MakeTime(hour, minute, second, now.Month, now.Day, now.Year, -1);
@@ -1470,7 +1470,7 @@ public static int MakeTime(int hour, int minute, int second)
/// The month.
/// Unix timestamp.
[ImplementsFunction("mktime")]
- public static int MakeTime(int hour, int minute, int second, int month)
+ public static long MakeTime(int hour, int minute, int second, int month)
{
DateTime now = Now;
return MakeTime(hour, minute, second, month, now.Day, now.Year, -1);
@@ -1487,7 +1487,7 @@ public static int MakeTime(int hour, int minute, int second, int month)
/// The day.
/// Unix timestamp.
[ImplementsFunction("mktime")]
- public static int MakeTime(int hour, int minute, int second, int month, int day)
+ public static long MakeTime(int hour, int minute, int second, int month, int day)
{
DateTime now = Now;
return MakeTime(hour, minute, second, month, day, now.Year, -1);
@@ -1504,7 +1504,7 @@ public static int MakeTime(int hour, int minute, int second, int month, int day)
/// The year.
/// Unix timestamp.
[ImplementsFunction("mktime")]
- public static int MakeTime(int hour, int minute, int second, int month, int day, int year)
+ public static long MakeTime(int hour, int minute, int second, int month, int day, int year)
{
return MakeTime(hour, minute, second, month, day, year, -1);
}
@@ -1521,7 +1521,7 @@ public static int MakeTime(int hour, int minute, int second, int month, int day,
/// Daylight savings time.
/// Unix timestamp.
[ImplementsFunction("mktime")]
- public static int MakeTime(int hour, int minute, int second, int month, int day, int year, int daylightSaving)
+ public static long MakeTime(int hour, int minute, int second, int month, int day, int year, int daylightSaving)
{
var zone = PhpTimeZone.CurrentTimeZone;
DateTime local = MakeDateTime(hour, minute, second, month, day, year);
@@ -1662,7 +1662,7 @@ public static PhpArray GetDate()
/// Number of seconds since 1970.
/// Associative array with date information.
[ImplementsFunction("getdate")]
- public static PhpArray GetDate(int timestamp)
+ public static PhpArray GetDate(long timestamp)
{
return GetDate(DateTimeUtils.UnixTimeStampToUtc(timestamp));
}
@@ -1816,7 +1816,7 @@ public static PhpArray GetLocalTime()
/// Number of seconds since 1970.
/// Array containing values specifying the date and time.
[ImplementsFunction("localtime")]
- public static PhpArray GetLocalTime(int timestamp)
+ public static PhpArray GetLocalTime(long timestamp)
{
return GetLocalTime(DateTimeUtils.UnixTimeStampToUtc(timestamp), false);
}
@@ -1846,7 +1846,7 @@ public static PhpArray GetLocalTime(int timestamp)
///
///
[ImplementsFunction("localtime")]
- public static PhpArray GetLocalTime(int timestamp, bool returnAssociative)
+ public static PhpArray GetLocalTime(long timestamp, bool returnAssociative)
{
return GetLocalTime(DateTimeUtils.UnixTimeStampToUtc(timestamp), returnAssociative);
}
@@ -1985,13 +1985,13 @@ public static object StringToTime(string time)
/// Timestamp (seconds from 1970) to which is the new timestamp counted.
/// Number of seconds since 1/1/1970 or -1 on failure.
[ImplementsFunction("strtotime")]
- public static object StringToTime(string time, int start)
+ public static object StringToTime(string time, long start)
{
return StringToTime(time, DateTimeUtils.UnixTimeStampToUtc(start));
}
///
- /// Implementation of function.
+ /// Implementation of function.
///
private static object StringToTime(string time, DateTime startUtc)
{
@@ -2000,7 +2000,7 @@ private static object StringToTime(string time, DateTime startUtc)
if (time.Length == 0) return false;
string error = null;
- int result = StrToTime.DateInfo.Parse(time, startUtc, out error);
+ long result = StrToTime.DateInfo.Parse(time, startUtc, out error);
if (error != null)
{
PhpException.Throw(PhpError.Warning, error);
@@ -2019,7 +2019,7 @@ private static object StringToTime(string time, DateTime startUtc)
///
/// Number of seconds since 1970.
[ImplementsFunction("time")]
- public static int Time()
+ public static long Time()
{
return DateTimeUtils.UtcToUnixTimeStamp(DateTime.UtcNow);
}
@@ -2039,79 +2039,79 @@ public enum TimeFormats
}
[ImplementsFunction("date_sunrise")]
- public static object GetSunriseTime(int timestamp)
+ public static object GetSunriseTime(long timestamp)
{
return GetSunTime(timestamp, TimeFormats.String, Double.NaN, Double.NaN, Double.NaN, Double.NaN, true);
}
[ImplementsFunction("date_sunrise")]
- public static object GetSunriseTime(int timestamp, TimeFormats format)
+ public static object GetSunriseTime(long timestamp, TimeFormats format)
{
return GetSunTime(timestamp, format, Double.NaN, Double.NaN, Double.NaN, Double.NaN, true);
}
- [ImplementsFunction("date_sunrise")]
- public static object GetSunriseTime(int timestamp, TimeFormats format, double latitude)
+ [ImplementsFunction("date_sunrise")]
+ public static object GetSunriseTime(long timestamp, TimeFormats format, double latitude)
{
return GetSunTime(timestamp, format, latitude, Double.NaN, Double.NaN, Double.NaN, true);
}
- [ImplementsFunction("date_sunrise")]
- public static object GetSunriseTime(int timestamp, TimeFormats format, double latitude, double longitude)
+ [ImplementsFunction("date_sunrise")]
+ public static object GetSunriseTime(long timestamp, TimeFormats format, double latitude, double longitude)
{
return GetSunTime(timestamp, format, latitude, longitude, Double.NaN, Double.NaN, true);
}
- [ImplementsFunction("date_sunrise")]
- public static object GetSunriseTime(int timestamp, TimeFormats format, double latitude, double longitude, double zenith)
+ [ImplementsFunction("date_sunrise")]
+ public static object GetSunriseTime(long timestamp, TimeFormats format, double latitude, double longitude, double zenith)
{
return GetSunTime(timestamp, format, latitude, longitude, zenith, Double.NaN, true);
}
- [ImplementsFunction("date_sunrise")]
- public static object GetSunriseTime(int timestamp, TimeFormats format, double latitude, double longitude, double zenith, double offset)
+ [ImplementsFunction("date_sunrise")]
+ public static object GetSunriseTime(long timestamp, TimeFormats format, double latitude, double longitude, double zenith, double offset)
{
return GetSunTime(timestamp, format, latitude, longitude, zenith, offset, true);
}
- [ImplementsFunction("date_sunset")]
- public static object GetSunsetTime(int timestamp)
+ [ImplementsFunction("date_sunset")]
+ public static object GetSunsetTime(long timestamp)
{
return GetSunTime(timestamp, TimeFormats.String, Double.NaN, Double.NaN, Double.NaN, Double.NaN, false);
}
- [ImplementsFunction("date_sunset")]
- public static object GetSunsetTime(int timestamp, TimeFormats format)
+ [ImplementsFunction("date_sunset")]
+ public static object GetSunsetTime(long timestamp, TimeFormats format)
{
return GetSunTime(timestamp, format, Double.NaN, Double.NaN, Double.NaN, Double.NaN, false);
}
- [ImplementsFunction("date_sunset")]
- public static object GetSunsetTime(int timestamp, TimeFormats format, double latitude)
+ [ImplementsFunction("date_sunset")]
+ public static object GetSunsetTime(long timestamp, TimeFormats format, double latitude)
{
return GetSunTime(timestamp, format, latitude, Double.NaN, Double.NaN, Double.NaN, false);
}
- [ImplementsFunction("date_sunset")]
- public static object GetSunsetTime(int timestamp, TimeFormats format, double latitude, double longitude)
+ [ImplementsFunction("date_sunset")]
+ public static object GetSunsetTime(long timestamp, TimeFormats format, double latitude, double longitude)
{
return GetSunTime(timestamp, format, latitude, longitude, Double.NaN, Double.NaN, false);
}
- [ImplementsFunction("date_sunset")]
- public static object GetSunsetTime(int timestamp, TimeFormats format, double latitude, double longitude, double zenith)
+ [ImplementsFunction("date_sunset")]
+ public static object GetSunsetTime(long timestamp, TimeFormats format, double latitude, double longitude, double zenith)
{
return GetSunTime(timestamp, format, latitude, longitude, zenith, Double.NaN, false);
}
- [ImplementsFunction("date_sunset")]
- public static object GetSunsetTime(int timestamp, TimeFormats format, double latitude, double longitude, double zenith, double offset)
+ [ImplementsFunction("date_sunset")]
+ public static object GetSunsetTime(long timestamp, TimeFormats format, double latitude, double longitude, double zenith, double offset)
{
return GetSunTime(timestamp, format, latitude, longitude, zenith, offset, false);
- }
-
-
- public static object GetSunTime(int timestamp, TimeFormats format, double latitude, double longitude, double zenith, double offset, bool getSunrise)
+ }
+
+
+ public static object GetSunTime(long timestamp, TimeFormats format, double latitude, double longitude, double zenith, double offset, bool getSunrise)
{
var zone = PhpTimeZone.CurrentTimeZone;
DateTime utc = DateTimeUtils.UnixTimeStampToUtc(timestamp);
@@ -2263,11 +2263,11 @@ private static double CalculateSunTime(int day, double latitude, double longitud
struct StringToTimeCase
{
public string String;
- public int StartTime;
+ public long StartTime;
public string Result;
public TimeZoneInfo[] Zones;
- public StringToTimeCase(string str, int start, string result, TimeZoneInfo[] zones)
+ public StringToTimeCase(string str, long start, string result, TimeZoneInfo[] zones)
{
this.String = str;
this.StartTime = start;
diff --git a/Source/ClassLibrary/DateTime.CLR/DateTimeParsing.cs b/Source/ClassLibrary/DateTime.CLR/DateTimeParsing.cs
index af0ecb6e..ab16aa04 100644
--- a/Source/ClassLibrary/DateTime.CLR/DateTimeParsing.cs
+++ b/Source/ClassLibrary/DateTime.CLR/DateTimeParsing.cs
@@ -116,7 +116,7 @@ public struct Relative
#region Parse
- public static int Parse(string/*!*/ str, DateTime utcStart, out string error)
+ public static long Parse(string/*!*/ str, DateTime utcStart, out string error)
{
Debug.Assert(str != null);
@@ -141,7 +141,7 @@ public static int Parse(string/*!*/ str, DateTime utcStart, out string error)
#region GetUnixTimeStamp
- private int GetUnixTimeStamp(DateTime utcStart, out string error)
+ private long GetUnixTimeStamp(DateTime utcStart, out string error)
{
var zone = PhpTimeZone.CurrentTimeZone;
DateTime start = TimeZoneInfo.ConvertTimeFromUtc(utcStart, zone);// zone.ToLocalTime(utcStart);
diff --git a/Source/ClassLibrary/FileSystem.CLR.cs b/Source/ClassLibrary/FileSystem.CLR.cs
index 79ae0f88..9b83b24a 100644
--- a/Source/ClassLibrary/FileSystem.CLR.cs
+++ b/Source/ClassLibrary/FileSystem.CLR.cs
@@ -55,6 +55,8 @@ private static void Clear()
statCacheUrl = null;
}
+ private static char[] invalidPathChars = Path.GetInvalidPathChars();
+
#endregion
#region Stat Basics (BuildStatArray, StatInternal, lstat, stat, fstat, clearstatcache; exists, touch)
@@ -510,11 +512,11 @@ public static string GetType(string path)
/// The file access time or -1 in case of failure.
[ImplementsFunction("fileatime")]
[return: CastToFalse]
- public static int GetAccessTime(string path)
+ public static long GetAccessTime(string path)
{
bool ok = StatInternal(path, false);
if (!ok) return -1;
- return unchecked((int)statCache.st_atime);
+ return statCache.st_atime;
}
///
@@ -666,7 +668,7 @@ public static bool IsDirectory(string path)
{
StreamWrapper wrapper;
- if (!string.IsNullOrEmpty(path) && StatInternalCheck(ref path, false, out wrapper)) // do not throw warning if path is null or empty
+ if (!string.IsNullOrEmpty(path) && path.IndexOfAny(invalidPathChars) < 0 && StatInternalCheck(ref path, false, out wrapper)) // do not throw warning if path is null or empty
{
string url;
if (StatInternalTryCache(path, out url))
@@ -693,7 +695,7 @@ public static bool IsDirectory(string path)
[ImplementsFunction("is_executable")]
public static bool IsExecutable(string path)
{
- bool ok = StatInternal(path, false);
+ bool ok = !string.IsNullOrEmpty(path) && path.IndexOfAny(invalidPathChars) < 0 && StatInternal(path, false);
if (!ok) return false;
return ((FileModeFlags)statCache.st_mode & FileModeFlags.Execute) > 0;
}
@@ -708,7 +710,7 @@ public static bool IsFile(string path)
{
StreamWrapper wrapper;
- if (StatInternalCheck(ref path, false, out wrapper))
+ if (!string.IsNullOrEmpty(path) && path.IndexOfAny(invalidPathChars) < 0 && StatInternalCheck(ref path, false, out wrapper))
{
string url;
if (StatInternalTryCache(path, out url))
@@ -744,7 +746,7 @@ public static bool IsLink(string path)
[ImplementsFunction("is_readable")]
public static bool IsReadable(string path)
{
- bool ok = StatInternal(path, false);
+ bool ok = !string.IsNullOrEmpty(path) && path.IndexOfAny(invalidPathChars) < 0 && StatInternal(path, false);
if (!ok) return false;
return ((FileModeFlags)statCache.st_mode & FileModeFlags.Read) > 0;
}
@@ -769,7 +771,7 @@ public static bool IsWriteable(string path)
[ImplementsFunction("is_writable")]
public static bool IsWritable(string path)
{
- bool ok = StatInternal(path, false);
+ bool ok = !string.IsNullOrEmpty(path) && path.IndexOfAny(invalidPathChars) < 0 && StatInternal(path, false);
if (!ok) return false;
return ((FileModeFlags)statCache.st_mode & FileModeFlags.Write) > 0;
}
diff --git a/Source/ClassLibrary/Miscellaneous.cs b/Source/ClassLibrary/Miscellaneous.cs
index f84a3fc0..b0f84c86 100644
--- a/Source/ClassLibrary/Miscellaneous.cs
+++ b/Source/ClassLibrary/Miscellaneous.cs
@@ -378,7 +378,7 @@ public static int GetCurrentProcessId()
///
/// The UNIX timestamp or -1 on error.
[ImplementsFunction("getlastmod")]
- public static int GetLastModification()
+ public static long GetLastModification()
{
try
{
diff --git a/Source/ClassLibrary/Output.CLR.cs b/Source/ClassLibrary/Output.CLR.cs
index c1b7701c..9ff55084 100644
--- a/Source/ClassLibrary/Output.CLR.cs
+++ b/Source/ClassLibrary/Output.CLR.cs
@@ -332,7 +332,22 @@ public static PhpArray GetStatus(bool full)
public static void FlushHttpBuffers()
{
HttpContext http_context = HttpContext.Current;
- if (http_context != null) http_context.Response.Flush();
+ if (http_context != null)
+ {
+ try
+ {
+ http_context.Response.Flush();
+ }
+ catch (HttpException)
+ {
+ var context = RequestContext.CurrentContext;
+ if (context != null && !context.TrackClientDisconnection)
+ {
+ return;
+ }
+ throw;
+ }
+ }
}
///
diff --git a/Source/ClassLibrary/Session.CLR.cs b/Source/ClassLibrary/Session.CLR.cs
index b7425d0d..467f52cc 100644
--- a/Source/ClassLibrary/Session.CLR.cs
+++ b/Source/ClassLibrary/Session.CLR.cs
@@ -213,7 +213,7 @@ protected override void Collect(string savePath, string sid, int lifetime)
{
if (dir == null) return;
- int threshold = DateTimeUtils.UtcToUnixTimeStamp(DateTime.Now.ToUniversalTime().AddSeconds(-lifetime));
+ long threshold = DateTimeUtils.UtcToUnixTimeStamp(DateTime.Now.ToUniversalTime().AddSeconds(-lifetime));
string file_name;
while ((file_name = PhpDirectory.Read(dir)) != null)
@@ -221,7 +221,7 @@ protected override void Collect(string savePath, string sid, int lifetime)
if (file_name.Length >= FilePrefix.Length && file_name.Substring(0, FilePrefix.Length) == FilePrefix)
{
string full_path = Path.Combine(savePath, file_name);
- int time = PhpFile.GetAccessTime(full_path);
+ long time = PhpFile.GetAccessTime(full_path);
if (time < threshold)
{
diff --git a/Source/ClassLibrary/Web.cs b/Source/ClassLibrary/Web.cs
index 8bdac944..468c6665 100644
--- a/Source/ClassLibrary/Web.cs
+++ b/Source/ClassLibrary/Web.cs
@@ -378,7 +378,7 @@ public static string RawUrlEncode(string str)
[ImplementsFunction("urldecode")]
public static string UrlDecode(string str)
{
- return HttpUtility.UrlDecode(str);
+ return HttpUtility.UrlDecode(str, Configuration.Application.Globalization.PageEncoding);
}
///
@@ -387,7 +387,7 @@ public static string UrlDecode(string str)
[ImplementsFunction("urlencode")]
public static string UrlEncode(string str)
{
- return UpperCaseEncodedChars(HttpUtility.UrlEncode(str));
+ return UpperCaseEncodedChars(HttpUtility.UrlEncode(str, Configuration.Application.Globalization.PageEncoding));
}
private static string UpperCaseEncodedChars(string encoded)
diff --git a/Source/Core/Compiler/AppCompiler.CLR.cs b/Source/Core/Compiler/AppCompiler.CLR.cs
index 64f230a3..9f26a874 100644
--- a/Source/Core/Compiler/AppCompiler.CLR.cs
+++ b/Source/Core/Compiler/AppCompiler.CLR.cs
@@ -1324,7 +1324,7 @@ public static bool IsPureUnit(string/*!*/ value)
}
PhpAssemblyBuilder assembly_builder = PhpAssemblyBuilder.Create(applicationContext, kind, ps.Pure, ps.OutPath,
- ps.DocPath, entry_point_file, ps.Version, ps.Key, ps.Icon, resource_files, config.Compiler.Debug, ps.Force32Bit);
+ ps.DocPath, entry_point_file, ps.Version, ps.Key, ps.Icon, resource_files, config.Compiler.DebugMode, ps.Force32Bit);
assembly_builder.IsMTA = ps.IsMTA;
diff --git a/Source/Core/Compiler/CodeGenerator/CodeGenerator.cs b/Source/Core/Compiler/CodeGenerator/CodeGenerator.cs
index 7f010ca1..1129537e 100644
--- a/Source/Core/Compiler/CodeGenerator/CodeGenerator.cs
+++ b/Source/Core/Compiler/CodeGenerator/CodeGenerator.cs
@@ -2950,7 +2950,7 @@ internal void EmitPhpException(ILEmitter/*!*/ il, MethodInfo/*!*/ method)
/// Real last column of the point.
internal void MarkSequencePoint(int startLine, int startColumn, int endLine, int endColumn)
{
- if (context.Config.Compiler.Debug)
+ if (context.Config.Compiler.DebugMode != DebugMode.None)
{
// ignores #pragma inside the code span:
ISymbolDocumentWriter symbol_writer = sourceUnit.GetMappedSymbolDocumentWriter(startLine);
@@ -2971,7 +2971,7 @@ internal void MarkSequencePoint(int startLine, int startColumn, int endLine, int
}
}
- ///
+ ///
/// Marks a sequence point (see ) using position of given .
///
/// Expression which position is used to mark sequence point.
diff --git a/Source/Core/Compiler/WebServerManagers.CLR.cs b/Source/Core/Compiler/WebServerManagers.CLR.cs
index 52384f70..eae44548 100644
--- a/Source/Core/Compiler/WebServerManagers.CLR.cs
+++ b/Source/Core/Compiler/WebServerManagers.CLR.cs
@@ -381,7 +381,7 @@ public IPhpModuleBuilder DefineModuleBuilder(CompilationUnitBase/*!*/ compiledUn
// creates a script assembly builder:
SingleScriptAssemblyBuilder builder = new SingleScriptAssemblyBuilder(applicationContext,
- name, outDir, name.Name + AssemblyExt, AssemblyKinds.WebPage, context.Config.Compiler.Debug, false, context.SaveOnlyAssembly, null);
+ name, outDir, name.Name + AssemblyExt, AssemblyKinds.WebPage, context.Config.Compiler.DebugMode, false, context.SaveOnlyAssembly, null);
return builder.DefineScript(unit);
}
diff --git a/Source/Core/Configuration.CLR.cs b/Source/Core/Configuration.CLR.cs
index 230c0a9c..c1d03d2c 100644
--- a/Source/Core/Configuration.CLR.cs
+++ b/Source/Core/Configuration.CLR.cs
@@ -851,7 +851,15 @@ internal int HashCode
hashcode += mapping.Pattern.ToString().GetHashCode();
hashcode += mapping.Replacement.GetHashCode();
}
- hashcode += debug ? 897987897 : 12;
+ if (debug)
+ {
+ hashcode += 897987897;
+ }
+ else
+ {
+ hashcode += 12;
+ hashcode += genegatePdbInRelease ? 564456654 : 35;
+ }
}
dirty = false;
@@ -873,6 +881,7 @@ internal CompilerSection()
dirty = true;
hashcode = 0;
debug = true;
+ genegatePdbInRelease = true;
disabledWarnings = WarningGroups.DeferredToRuntime | WarningGroups.CompilerStrict;
disabledWarningNumbers = ArrayUtils.EmptyIntegers;
@@ -979,6 +988,10 @@ public bool Parse(string name, string value, XmlNode node)
debug = (value == "true");
return true;
+ case "GeneratePdbInRelease":
+ genegatePdbInRelease = (value == "true");
+ return true;
+
case "WatchSourceChanges":
{
// applicable only in run-time:
diff --git a/Source/Core/Configuration.cs b/Source/Core/Configuration.cs
index b40685da..7b3ef405 100644
--- a/Source/Core/Configuration.cs
+++ b/Source/Core/Configuration.cs
@@ -16,6 +16,12 @@
namespace PHP.Core
{
+ public enum DebugMode
+ {
+ None,
+ Pdb,
+ Full
+ }
#region Language Features Enum
///
@@ -222,7 +228,14 @@ public sealed partial class OutputControlSection : IPhpConfigurationSection
internal OutputControlSection DeepCopy()
{
- return (OutputControlSection)MemberwiseClone();
+ return new OutputControlSection()
+ {
+ charSet = charSet,
+ contentType = contentType,
+ implicitFlush = implicitFlush,
+ outputBuffering = outputBuffering,
+ outputHandler = outputHandler == null ? null : outputHandler.DeepCopy()
+ };
}
}
@@ -337,7 +350,12 @@ private static string AbsolutizeLogFile(string value, System.Xml.XmlNode/*!*/nod
///
internal ErrorControlSection DeepCopy()
{
- return (ErrorControlSection)this.MemberwiseClone();
+ var copy = (ErrorControlSection)MemberwiseClone();
+ if (UserExceptionHandler != null)
+ copy.UserExceptionHandler = UserExceptionHandler.DeepCopy();
+ if (UserHandler != null)
+ copy.UserHandler = UserHandler.DeepCopy();
+ return copy;
}
}
@@ -422,7 +440,10 @@ public sealed partial class AssertionSection : IPhpConfigurationSection
///
internal AssertionSection DeepCopy()
{
- return (AssertionSection)this.MemberwiseClone();
+ var copy = (AssertionSection) MemberwiseClone();
+ if (Callback != null)
+ copy.Callback = Callback.DeepCopy();
+ return copy;
}
}
@@ -503,7 +524,12 @@ public static bool ValidateRegisteringOrder(string value)
///
internal VariablesSection DeepCopy()
{
- return (VariablesSection)this.MemberwiseClone();
+ var copy = (VariablesSection) MemberwiseClone();
+ if (DeserializationCallback != null)
+ {
+ copy.DeserializationCallback = DeserializationCallback.DeepCopy();
+ }
+ return copy;
}
}
@@ -787,7 +813,34 @@ public bool Debug
}
internal bool debug;
- #endregion
+ public bool GenegatePdbInRelease {
+ get { return genegatePdbInRelease; }
+ set
+ {
+ genegatePdbInRelease = value;
+#if !SILVERLIGHT
+ dirty = true;
+#endif
+ }
+ }
+ internal bool genegatePdbInRelease;
+
+ public DebugMode DebugMode
+ {
+ get
+ {
+ DebugMode result;
+ if (debug)
+ result = DebugMode.Full;
+ else if (genegatePdbInRelease)
+ result = DebugMode.Pdb;
+ else
+ result = DebugMode.None;
+ return result;
+ }
+ }
+
+ #endregion
#region Inclusions
diff --git a/Source/Core/Emit/AssemblyBuilders.CLR.cs b/Source/Core/Emit/AssemblyBuilders.CLR.cs
index 7eda1953..b963607a 100644
--- a/Source/Core/Emit/AssemblyBuilders.CLR.cs
+++ b/Source/Core/Emit/AssemblyBuilders.CLR.cs
@@ -47,8 +47,8 @@ public bool IsExecutable
///
/// Whether the assembly contains debug information.
///
- public bool Debuggable { get { return debuggable; } }
- private readonly bool debuggable;
+ public DebugMode Debuggable { get { return debuggable; } }
+ private readonly DebugMode debuggable;
///
/// Whether saved assembly should be executed as 32-bit process on 64-bit environments.
@@ -91,7 +91,7 @@ public bool IsExecutable
#region Construction
protected PhpAssemblyBuilder(PhpAssembly/*!*/ assembly, AssemblyName assemblyName, string moduleName,
- string directory, string fileName, AssemblyKinds kind, ICollection resources, bool debug,
+ string directory, string fileName, AssemblyKinds kind, ICollection resources, DebugMode debug,
bool force32bit, bool saveOnlyAssembly, Win32IconResource icon)
: base(assembly)
{
@@ -109,7 +109,7 @@ public bool IsExecutable
#else
AssemblyBuilder assembly_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, saveOnlyAssembly ? AssemblyBuilderAccess.Save : AssemblyBuilderAccess.RunAndSave, directory);
- ModuleBuilder module_builder = assembly_builder.DefineDynamicModule(moduleName, fileName, debug);
+ ModuleBuilder module_builder = assembly_builder.DefineDynamicModule(moduleName, fileName, debug != DebugMode.None);
#endif
DefineGlobalType(module_builder);
assembly.WriteUp(module_builder, Path.Combine(directory, fileName)); // TODO: Combine can be avoided (pass path instead of directory + fileName)
@@ -186,7 +186,7 @@ public override void EmitCustomAttribute(CustomAttributeBuilder/*!*/ builder, AS
public static PhpAssemblyBuilder/*!*/ Create(ApplicationContext/*!*/ applicationContext, AssemblyKinds kind,
bool pure, FullPath outPath, FullPath docPath, PhpSourceFile entryPoint, Version version,
- StrongNameKeyPair key, Win32IconResource icon, ICollection resources, bool debug, bool force32bit)
+ StrongNameKeyPair key, Win32IconResource icon, ICollection resources, DebugMode debug, bool force32bit)
{
string out_dir = Path.GetDirectoryName(outPath);
string out_file = Path.GetFileName(outPath);
@@ -222,7 +222,7 @@ public void Save()
BakeGlobals();
// annotates the assembly with Debuggable attribute:
- if (debuggable)
+ if (debuggable == DebugMode.Full)
{
builder.SetCustomAttribute(new CustomAttributeBuilder(Constructors.Debuggable,
new object[] { true, true }));
@@ -377,7 +377,7 @@ private MethodInfo CreateEntryPoint()
RealAssemblyBuilder.SetEntryPoint(entry_method, Enums.ToPEFileKind(kind));
// user entry point can be defined only on module which is in debug mode:
- if (debuggable)
+ if (debuggable == DebugMode.Full)
ReflectionUtils.SetUserEntryPoint(RealModuleBuilder, GetUserEntryPointMethod());
return entry_method;
@@ -401,7 +401,7 @@ public sealed class PureAssemblyBuilder : PhpAssemblyBuilder
public override bool IsPure { get { return true; } }
public PureAssemblyBuilder(ApplicationContext/*!*/ applicationContext, AssemblyName assemblyName,
- string directory, string fileName, AssemblyKinds kind, ICollection resources, bool debug, bool force32bit, Win32IconResource icon)
+ string directory, string fileName, AssemblyKinds kind, ICollection resources, DebugMode debug, bool force32bit, Win32IconResource icon)
: base(new PureAssembly(applicationContext), assemblyName, PureAssembly.ModuleName, directory,
fileName, kind, resources, debug, force32bit, false, icon)
{
@@ -503,7 +503,7 @@ public abstract class ScriptAssemblyBuilder : PhpAssemblyBuilder
public ScriptAssembly/*!*/ ScriptAssembly { get { return (ScriptAssembly)assembly; } }
protected ScriptAssemblyBuilder(ScriptAssembly/*!*/ assembly, AssemblyName assemblyName, string directory,
- string fileName, AssemblyKinds kind, ICollection resources, bool debug,
+ string fileName, AssemblyKinds kind, ICollection resources, DebugMode debug,
bool force32bit, bool saveOnlyAssembly, Win32IconResource icon)
: base(assembly, assemblyName, ScriptAssembly.RealModuleName, directory, fileName, kind,resources, debug, force32bit, saveOnlyAssembly, icon)
{
@@ -635,7 +635,7 @@ internal class SingleScriptAssemblyBuilder : ScriptAssemblyBuilder
/// Icon resource or a null reference.
/// Resources to embed
public SingleScriptAssemblyBuilder(ApplicationContext/*!*/ applicationContext, AssemblyName assemblyName, string directory, string fileName,
- AssemblyKinds kind, ICollection resources, bool debug, bool force32bit, bool saveOnlyAssembly, Win32IconResource icon)
+ AssemblyKinds kind, ICollection resources, DebugMode debug, bool force32bit, bool saveOnlyAssembly, Win32IconResource icon)
: base(new SingleScriptAssembly(applicationContext), assemblyName, directory, fileName, kind, resources, debug, force32bit, saveOnlyAssembly, icon)
{
}
@@ -652,7 +652,7 @@ internal class SingleScriptAssemblyBuilder : ScriptAssemblyBuilder
/// Whether to not load the assembly into memory.
/// Icon resource or a null reference.
public SingleScriptAssemblyBuilder(ApplicationContext/*!*/ applicationContext, AssemblyName assemblyName, string directory, string fileName,
- AssemblyKinds kind, bool debug, bool force32bit, bool saveOnlyAssembly, Win32IconResource icon)
+ AssemblyKinds kind, DebugMode debug, bool force32bit, bool saveOnlyAssembly, Win32IconResource icon)
: base(new SingleScriptAssembly(applicationContext), assemblyName, directory, fileName, kind, null, debug, force32bit, saveOnlyAssembly, icon)
{
}
@@ -723,7 +723,7 @@ internal class MultiScriptAssemblyBuilder : ScriptAssemblyBuilder
/// Resources to embed
public MultiScriptAssemblyBuilder(ApplicationContext/*!*/ applicationContext, AssemblyName assemblyName,
string directory, string fileName, AssemblyKinds kind, ICollection resources,
- bool debug, bool force32bit, Win32IconResource icon, PhpSourceFile entryPoint)
+ DebugMode debug, bool force32bit, Win32IconResource icon, PhpSourceFile entryPoint)
: base(new MultiScriptAssembly(applicationContext), assemblyName, directory, fileName, kind, resources, debug, force32bit, false, icon)
{
this.entryPoint = entryPoint;
diff --git a/Source/Core/Emit/AssemblyBuilders.cs b/Source/Core/Emit/AssemblyBuilders.cs
index 7a98f570..b70e82ba 100644
--- a/Source/Core/Emit/AssemblyBuilders.cs
+++ b/Source/Core/Emit/AssemblyBuilders.cs
@@ -194,7 +194,7 @@ public sealed class TransientAssemblyBuilder : PhpAssemblyBuilderBase
private object initializationMutex = new object();
private volatile bool initialized = false;
- private bool debuggable = false;
+ private DebugMode debuggable = DebugMode.None;
#endregion
@@ -230,7 +230,7 @@ public TransientAssemblyBuilder(ApplicationContext/*!*/ applicationContext)
return result;
}
- private void InitializeRealAssembly(bool debuggable)
+ private void InitializeRealAssembly(DebugMode debuggable)
{
if (!initialized)
{
@@ -243,7 +243,7 @@ private void InitializeRealAssembly(bool debuggable)
// TODO: do we need sync?
AssemblyBuilder assembly_builder = AppDomain.CurrentDomain.DefineDynamicAssembly
(assembly_name, AssemblyBuilderAccess.Run);
- ModuleBuilder module_builder = assembly_builder.DefineDynamicModule(TransientAssembly.RealModuleName, debuggable);
+ ModuleBuilder module_builder = assembly_builder.DefineDynamicModule(TransientAssembly.RealModuleName, debuggable!=DebugMode.None);
assembly.WriteUp(module_builder, null);
@@ -258,7 +258,7 @@ private void InitializeRealAssembly(bool debuggable)
public TransientAssembly TransientAssembly { get { return (TransientAssembly)assembly; } }
- public TransientModuleBuilder/*!*/ DefineModule(TransientCompilationUnit/*!*/ compilationUnit, bool debuggable,
+ public TransientModuleBuilder/*!*/ DefineModule(TransientCompilationUnit/*!*/ compilationUnit, DebugMode debuggable,
int containerId, EvalKinds kind, string sourcePath)
{
InitializeRealAssembly(debuggable);
diff --git a/Source/Core/Errors.cs b/Source/Core/Errors.cs
index 813d4ba3..f582ea72 100644
--- a/Source/Core/Errors.cs
+++ b/Source/Core/Errors.cs
@@ -216,7 +216,7 @@ public static void ArgumentNull(string argument)
/// The name of the argument.
public static void ReferenceNull(string argument)
{
- Throw(PhpError.Error, CoreResources.GetString("reference_null", argument));
+ Throw(PhpError.Warning, CoreResources.GetString("reference_null", argument));
}
///
@@ -585,12 +585,12 @@ public static void PropertyTypeMismatch(string/*!*/ className, string/*!*/ prope
[ThreadStatic]
internal static Action ThrowCallbackOverride = null;
- ///
- /// Reports a PHP error.
- ///
- /// The error type
- /// The error message.
- public static void Throw(PhpError error, string message)
+ ///
+ /// Reports a PHP error.
+ ///
+ /// The error type
+ /// The error message.
+ public static void Throw(PhpError error, string message)
{
if (ThrowCallbackOverride != null)
{
@@ -607,7 +607,7 @@ public static void Throw(PhpError error, string message)
// determines whether the error will be reported and whether it is handleable:
bool is_error_reported = ((PhpErrorSet)error & config.ErrorControl.ReportErrors) != 0 && !context.ErrorReportingDisabled;
- bool is_error_handleable = ((PhpErrorSet)error & PhpErrorSet.Handleable & (PhpErrorSet)config.ErrorControl.UserHandlerErrors) != 0;
+ bool is_error_handleable = ((PhpErrorSet)error & PhpErrorSet.Handleable & (PhpErrorSet)config.ErrorControl.UserHandlerErrors) != 0;
bool is_error_fatal = ((PhpErrorSet)error & PhpErrorSet.Fatal) != 0;
bool do_report = true;
diff --git a/Source/Core/HttpHeaders.CLR.cs b/Source/Core/HttpHeaders.CLR.cs
index 422a4d09..16e86424 100644
--- a/Source/Core/HttpHeaders.CLR.cs
+++ b/Source/Core/HttpHeaders.CLR.cs
@@ -435,8 +435,13 @@ private class IntegratedPipelineHeaders : HttpHeaders
public IntegratedPipelineHeaders()
:base(false)
{
- if (httpContext != null)
- httpContext.Response.Headers["X-Powered-By"] = PoweredByHeader;
+ try
+ {
+ if (httpContext != null)
+ httpContext.Response.Headers["X-Powered-By"] = PoweredByHeader;
+ }
+ catch(HttpException) // integrated pipeline initialization mode
+ {}
}
#endregion
diff --git a/Source/Core/PhpBytes.cs b/Source/Core/PhpBytes.cs
index 7b068304..93eb7a88 100644
--- a/Source/Core/PhpBytes.cs
+++ b/Source/Core/PhpBytes.cs
@@ -195,35 +195,35 @@ internal void Unshare()
#region DebugView, DumpTo
- ///
- /// Dumps internal data, escapes non-ASCII characters.
- ///
- /// Output to dump to.
- private void DumpTo(System.IO.TextWriter/*!*/output)
- {
- Debug.Assert(output != null);
-
- const string hex_digs = "0123456789abcdef";
- char[] patch = new char[4] { '\\', 'x', '0', '0' };
-
- foreach (byte b in ReadonlyData)
- {
- // printable characters are outputted normally
- if (b < 0x7f)
- {
- output.Write((char)b);
- }
- else
- {
- patch[2] = hex_digs[(b & 0xf0) >> 4];
- patch[3] = hex_digs[(b & 0x0f)];
-
- output.Write(patch);
- }
- }
- }
-
- private string DebugView()
+ ///
+ /// Dumps internal data, escapes non-ASCII characters.
+ ///
+ /// Output to dump to.
+ private void DumpTo(System.IO.TextWriter /*!*/ output)
+ {
+ Debug.Assert(output != null);
+
+ const string hex_digs = "0123456789abcdef";
+ char[] patch = new char[4] {'\\', 'x', '0', '0'};
+
+ foreach (byte b in ReadonlyData)
+ {
+ // printable characters are outputted normally
+ if (b < 0x7f)
+ {
+ output.Write((char) b);
+ }
+ else
+ {
+ patch[2] = hex_digs[(b & 0xf0) >> 4];
+ patch[3] = hex_digs[(b & 0x0f)];
+
+ output.Write(patch);
+ }
+ }
+ }
+
+ private string DebugView()
{
var output = new System.IO.StringWriter();
const string hex_digs = "0123456789ABCDEF";
@@ -421,9 +421,7 @@ string IPhpConvertible.ToString(bool throwOnError, out bool success)
/// The output text stream.
public void Print(System.IO.TextWriter output)
{
- output.Write("\"");
- DumpTo(output);
- output.WriteLine("\"");
+ output.Write(ToString());
}
///
diff --git a/Source/Core/PhpCallback.cs b/Source/Core/PhpCallback.cs
index 97fabf6c..0d9ae472 100644
--- a/Source/Core/PhpCallback.cs
+++ b/Source/Core/PhpCallback.cs
@@ -583,7 +583,14 @@ string IPhpConvertible.ToString()
}
}
- ///
+ public PhpCallback DeepCopy()
+ {
+ Debug.Assert(!IsBound); //bounded callbacks are not supported
+
+ return (PhpCallback)MemberwiseClone();
+ }
+
+ ///
/// Converts instance to its string representation according to PHP conversion algorithm.
///
/// Indicates whether conversion was successful.
diff --git a/Source/Core/Reflection/CompilationUnits.cs b/Source/Core/Reflection/CompilationUnits.cs
index 6d9af36a..079f437c 100644
--- a/Source/Core/Reflection/CompilationUnits.cs
+++ b/Source/Core/Reflection/CompilationUnits.cs
@@ -315,7 +315,7 @@ public override DConstant GetVisibleConstant(QualifiedName qualifiedName, ref st
// .. but we don't know whether it will be dynamic in advance!
this.assembly_builder = scriptContext.ApplicationContext.TransientAssemblyBuilder;
- this.module_builder = assembly_builder.DefineModule(this, context.Config.Compiler.Debug,
+ this.module_builder = assembly_builder.DefineModule(this, context.Config.Compiler.DebugMode,
descriptor.ContainingTransientModuleId, kind, descriptor.ContainingSourcePath);
this.module = module_builder;
this.evalKind = kind;
diff --git a/Source/Core/ScriptContext.CLR.cs b/Source/Core/ScriptContext.CLR.cs
index 19c72201..4b8d82dc 100644
--- a/Source/Core/ScriptContext.CLR.cs
+++ b/Source/Core/ScriptContext.CLR.cs
@@ -266,7 +266,7 @@ public static void RunApplication(Delegate/*!*/ mainRoutine, string relativeSour
output = Stream.Null;
context.OutputStream = output;
- context.Output = new StreamWriter(output);
+ context.Output = new StreamWriter(output, Configuration.Application.Globalization.PageEncoding);
return context;
}
@@ -338,12 +338,11 @@ public static ScriptContext CurrentContext
try
{
return ((ScriptContext)CallContext.GetData(callContextSlotName)) ?? CreateDefaultScriptContext(); // on Mono, .GetData must be used (GetLogicalData is not implemented)
- }
+ }
catch (InvalidCastException)
{
throw new InvalidCallContextDataException(callContextSlotName);
}
-
//return result.AttachToHttpApplication();
}
set
@@ -352,10 +351,28 @@ public static ScriptContext CurrentContext
CallContext.FreeNamedDataSlot(callContextSlotName);
else
CallContext.SetData(callContextSlotName, value); // on Mono, .SetData must be used (SetLogicalData is not implemented)
- }
+ }
}
///
+
+ public static ScriptContext CurrentContextOrNull
+ {
+ [Emitted]
+ get
+ {
+ try
+ {
+ return (ScriptContext)CallContext.GetData(callContextSlotName); // on Mono, .GetData must be used (GetLogicalData is not implemented)
+ }
+ catch (InvalidCastException)
+ {
+ throw new InvalidCallContextDataException(callContextSlotName);
+ };
+ }
+ }
+
+ ///
/// Initialize new ScriptContext and store it into the LogicalCallContext.
///
/// Newly created ScriptContext.
diff --git a/Source/Core/ScriptContext.cs b/Source/Core/ScriptContext.cs
index a5c1a1d0..b57479ed 100644
--- a/Source/Core/ScriptContext.cs
+++ b/Source/Core/ScriptContext.cs
@@ -12,6 +12,7 @@
using System;
using System.IO;
+using System.Runtime.ExceptionServices;
using System.Text;
using System.Threading;
using System.Reflection;
@@ -462,6 +463,34 @@ public string[] SplAutoloadExtensions
#region Construction
+ static ScriptContext()
+ {
+ AppDomain.CurrentDomain.FirstChanceException+=CurrentDomainOnFirstChanceException;
+ }
+
+ private static void CurrentDomainOnFirstChanceException(object sender, FirstChanceExceptionEventArgs args)
+ {
+ if (args.Exception is ThreadAbortException)
+ {
+ try
+ {
+ var context = CurrentContextOrNull;
+ if (context == null || !context.ExecutionTimedOut)
+ return;
+ bool old_throw = context.ThrowExceptionOnError;
+ context.ThrowExceptionOnError = false;
+
+ PhpException.Throw(
+ PhpError.Error,
+ CoreResources.GetString("execution_timed_out", context.config.RequestControl.ExecutionTimeout) + new StackTrace());
+
+ context.ThrowExceptionOnError = old_throw;
+ }
+ catch
+ { }
+ }
+ }
+
///
/// Creates an instance of initialized with dummy streams and
/// a copy of the default local configuration.
@@ -2160,7 +2189,9 @@ public void ApplyExecutionTimeout(int seconds)
catch (ThreadAbortException)
{
if (!executionTimedOut) throw;
- ThreadAbortedDueToTimeout();
+#if !SILVERLIGHT
+ Thread.ResetAbort();
+#endif
}
catch (PhpException)
{
@@ -2265,7 +2296,7 @@ private object GuardedMain(object/*!*/ mainRoutine)
///
/// Flushes all remaining data from output buffers.
///
- internal object FinalizeBufferedOutput(object _)
+ internal object FinalizeOutput(object _)
{
// flushes output, applies user defined output filter, and disables buffering:
if (bufferedOutput != null)
@@ -2274,33 +2305,17 @@ internal object FinalizeBufferedOutput(object _)
// redirects sinks:
IsOutputBuffered = false;
- return null;
- }
-
- ///
- /// Called when the execution has been timed out.
- ///
- private void ThreadAbortedDueToTimeout()
- {
- Debug.Assert(executionTimedOut);
-
-#if !SILVERLIGHT
- Thread.ResetAbort();
-#endif
-
- bool old_throw = ThrowExceptionOnError;
- ThrowExceptionOnError = false;
+ // flush unbuffered output
+ output.Flush();
- PhpException.Throw(PhpError.Error, CoreResources.GetString("execution_timed_out",
- config.RequestControl.ExecutionTimeout));
-
- ThrowExceptionOnError = old_throw;
+ return null;
}
// GENERICS: Lambda
private void TimedOut(object/*!*/ thread)
{
executionTimedOut = true;
+
((Thread)thread).Abort();
}
@@ -2913,7 +2928,7 @@ void IDisposable.Dispose()
{
this.GuardedCall
/// Time.
/// Unix timestamp.
- public static int UtcToUnixTimeStamp(DateTime dt)
+ public static long UtcToUnixTimeStamp(DateTime dt)
{
double seconds = (dt - UtcStartOfUnixEpoch).TotalSeconds;
- if (seconds < Int32.MinValue)
- return Int32.MinValue;
- if (seconds > Int32.MaxValue)
- return Int32.MaxValue;
+ if (seconds < Int64.MinValue)
+ return Int64.MinValue;
+ if (seconds > Int64.MaxValue)
+ return Int64.MaxValue;
- return (int)seconds;
+ return (long)seconds;
}
///
@@ -3842,7 +3842,7 @@ public static int UtcToUnixTimeStamp(DateTime dt)
///
/// UNIX timestamp
/// structure representing UTC time.
- public static DateTime UnixTimeStampToUtc(int timestamp)
+ public static DateTime UnixTimeStampToUtc(long timestamp)
{
return UtcStartOfUnixEpoch + TimeSpan.FromSeconds(timestamp);
}
diff --git a/Source/Extensions/Curl/CurlHttp.cs b/Source/Extensions/Curl/CurlHttp.cs
index 31305171..5f653a0f 100644
--- a/Source/Extensions/Curl/CurlHttp.cs
+++ b/Source/Extensions/Curl/CurlHttp.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using System.Net;
+using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
@@ -74,6 +75,11 @@ internal override object Execute(PhpCurlResource curl, ref CURLcode result)
for (; ; )
{
request = (HttpWebRequest)HttpWebRequest.Create(uri);
+ if (!string.IsNullOrWhiteSpace(uri.UserInfo))
+ {
+ var arr = uri.UserInfo.Split(new[] {':'}, 2);
+ request.Credentials = new NetworkCredential(arr[0], arr[1]);
+ }
Curl_HttpReq httpreq = (redirectAttempts == 0) || keepVerb ? setRequestMethod(data) : Curl_HttpReq.GET;
setTimeOut(data);
@@ -95,6 +101,18 @@ internal override object Execute(PhpCurlResource curl, ref CURLcode result)
setCredentials(data);
setCookies(data);
+#if NET45
+ request.ServerCertificateValidationCallback = (sender, certificate, chain, errors) =>
+ {
+ if (data.Ssl.VerifyPeer && (errors & SslPolicyErrors.RemoteCertificateChainErrors) == SslPolicyErrors.RemoteCertificateChainErrors)
+ return false;
+ if (data.Ssl.VerifyHost > 0 && (errors & SslPolicyErrors.RemoteCertificateNameMismatch) == SslPolicyErrors.RemoteCertificateNameMismatch)
+ // VerifyHost==1 removed in curl
+ return false;
+ return true;
+ };
+#endif
+
//ssl.VerifyPeer && ssl.VerifyHost == 2 is supported by default .NET
// other values are currently unsupported
diff --git a/Source/Extensions/Curl/HttpFormDataUploader.cs b/Source/Extensions/Curl/HttpFormDataUploader.cs
index 49166cd5..e25d95da 100644
--- a/Source/Extensions/Curl/HttpFormDataUploader.cs
+++ b/Source/Extensions/Curl/HttpFormDataUploader.cs
@@ -7,6 +7,7 @@
using System.IO;
using System.Threading;
using System.Security;
+using Convert = PHP.Core.Convert;
namespace PHP.Library.Curl
{
@@ -113,7 +114,7 @@ private void AddFormData(object data)
{
//currentData.Type = FormType.FORM_CONTENT;
- PhpBytes bytes = PhpVariable.AsBytes(data);
+ PhpBytes bytes = Convert.ObjectToPhpBytes(data);
currentData.Data = bytes.ReadonlyData;
NextDataIsFooter();
diff --git a/Source/Extensions/Curl/UserDefined.cs b/Source/Extensions/Curl/UserDefined.cs
index 98864fc2..5366d946 100644
--- a/Source/Extensions/Curl/UserDefined.cs
+++ b/Source/Extensions/Curl/UserDefined.cs
@@ -959,10 +959,10 @@ public CURLcode SetOption(CurlOption option, object value)
/*
* Enable peer SSL verifying.
*/
-
+#if !NET45
if (((bool)value) == false)
PhpException.ArgumentValueNotSupported("value", false);
-
+#endif
ssl.VerifyPeer = (bool)value;
break;
@@ -972,9 +972,10 @@ public CURLcode SetOption(CurlOption option, object value)
* Enable verification of the CN contained in the peer certificate
*/
+#if !NET45
if (((int)value) != 2)
PhpException.ArgumentValueNotSupported("value", (int)value);
-
+#endif
ssl.VerifyHost = (int)value;
break;
@@ -1099,6 +1100,10 @@ public CURLcode SetOption(CurlOption option, object value)
httpreq = Curl_HttpReq.POST_FORM;
opt_no_body = false; /* this is implied */
break;
+ case CurlOption.CURLOPT_NOSIGNAL:
+ case CurlOption.CURLOPT_SSLVERSION:
+ // this options can be safely ignored
+ break;
#region UNSUPPORTED OPTIONS
diff --git a/Source/Extensions/Gd2/PhpGd.cs b/Source/Extensions/Gd2/PhpGd.cs
index 97af6a8d..62f72750 100644
--- a/Source/Extensions/Gd2/PhpGd.cs
+++ b/Source/Extensions/Gd2/PhpGd.cs
@@ -714,12 +714,24 @@ public static bool imagecolormatch(PhpResource im1, PhpResource im2)
///
/// Get the index of the specified color or its closest possible alternative
///
- [ImplementsFunction("imagecolorresolve", FunctionImplOptions.NotSupported)]
+ [ImplementsFunction("imagecolorresolve")]
public static int imagecolorresolve(PhpResource im, int red, int green, int blue)
{
- //TODO: (Maros) Used in non-truecolor images (palette images).
- //PhpException.FunctionNotSupported(PhpError.Warning);
- return -1;
+ var im1 = (PhpGdImageResource) im;
+ var minValue = int.MaxValue;
+ var color = Color.FromArgb(red, green, blue);
+ int minIndex = -1;
+ for (int i = 0; i < im1.Image.Palette.Entries.Length; i++)
+ {
+ var curColor = im1.Image.Palette.Entries[i];
+ var value = Math.Abs(curColor.A - color.A) + Math.Abs(curColor.B - color.B) + Math.Abs(curColor.G - color.G) + Math.Abs(curColor.R - color.R);
+ if (value < minValue)
+ {
+ value = minValue;
+ minIndex = i;
+ }
+ }
+ return minIndex;
}
#endregion
@@ -758,11 +770,26 @@ public static void imagecolorset(PhpResource im, int col, int red, int green, in
///
/// Get the colors for an index
///
- [ImplementsFunction("imagecolorsforindex", FunctionImplOptions.NotSupported)]
+ [ImplementsFunction("imagecolorsforindex")]
public static PhpArray imagecolorsforindex(PhpResource im, int col)
{
- //PhpException.FunctionNotSupported(PhpError.Warning);
- return null;
+ var im1 = (PhpGdImageResource) im;
+ var arr = new PhpArray();
+ var entries = im1.Image.Palette.Entries;
+ Color color;
+ if (entries.Length > 0)
+ {
+ color = entries[col];
+ }
+ else
+ {
+ color = Color.FromArgb(col);
+ }
+ arr["red"] = (int)color.R;
+ arr["green"] = (int)color.G;
+ arr["blue"] = (int)color.B;
+ arr["alpha"] = (int)color.A;
+ return arr;
}
#endregion
@@ -3308,8 +3335,16 @@ private static PhpResource CreateGdImageFrom(string filename, ImageFormat format
Bitmap image = LoadBitmap(filename, format);
if (image == null)
return null;
-
- return new PhpGdImageResource(image);
+
+ var result = new PhpGdImageResource(image);
+ var color = image.Palette.Entries.Where(a => a.A < 255).Take(1).ToArray();
+ if (color.Length > 0)
+ {
+ result.transparentColor = color[0];
+ result.IsTransparentColSet = true;
+ result.SaveAlpha = true;
+ }
+ return result;
}
///
diff --git a/Source/Extensions/Gd2/PhpImage.cs b/Source/Extensions/Gd2/PhpImage.cs
index de10babd..af10fe2b 100644
--- a/Source/Extensions/Gd2/PhpImage.cs
+++ b/Source/Extensions/Gd2/PhpImage.cs
@@ -767,8 +767,19 @@ private static bool SkipVariable(Stream stream)
return false;
}
length = length - 2;
-
- stream.Seek(length, SeekOrigin.Current);
+ if (stream.CanSeek)
+ stream.Seek(length, SeekOrigin.Current);
+ else
+ {
+ var buffer = new byte[Math.Min(4*1024, length)];
+ do
+ {
+ var count = stream.Read(buffer, 0, Math.Min(length, buffer.Length));
+ length -= count;
+ if (count == 0)
+ return false;
+ } while (length > 0);
+ }
return true;
}
diff --git a/Source/Extensions/Soap/CodeConstants.cs b/Source/Extensions/Soap/CodeConstants.cs
index 3d76dc4d..c4803fb9 100644
--- a/Source/Extensions/Soap/CodeConstants.cs
+++ b/Source/Extensions/Soap/CodeConstants.cs
@@ -14,8 +14,11 @@ internal struct CodeConstants
internal const string END = "End";
internal const string CODENAMESPACE = "PHP.Library.Soap.DynamicProxy";
+ internal const string CODENAMESPACESERVER = "PHP.Library.Soap.Server";
internal const string DEFAULTBASETYPE = "System.Web.Services.Protocols.SoapHttpClientProtocol";
+ internal const string DEFAULTSERVERBASETYPE = "System.Web.Services.WebService";
internal const string CUSTOMBASETYPE = "PHP.Library.Soap.SoapHttpClientProtocolExtended";
+ internal const string CUSTOMSERVERBASETYPE = "PHP.Library.Soap.WebServiceExtended";
internal const string LIBTEMPDIR = "DynamicProxyTempDir";
internal const string TEMPDLLEXTENSION = "_soapclient_tmp.dll";
diff --git a/Source/Extensions/Soap/DynamicWebServiceProxy.cs b/Source/Extensions/Soap/DynamicWebServiceProxy.cs
index 1bbf6d39..9150b6db 100644
--- a/Source/Extensions/Soap/DynamicWebServiceProxy.cs
+++ b/Source/Extensions/Soap/DynamicWebServiceProxy.cs
@@ -2,16 +2,20 @@
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
+using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
+using System.Linq;
using System.Net;
using System.Reflection;
-using System.Security.Cryptography.X509Certificates;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;
using System.Web.Services.Description;
using System.Web.Services.Discovery;
+using System.Web.Services.Protocols;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
@@ -27,7 +31,7 @@ internal class DynamicWebServiceProxy
private Assembly ass;
private object proxyInstance;
private string wsdl;
- private string protocolName = "Soap";
+ private string protocolName = null;
private string proxySource;
private ServiceDescriptionImporter sdi;
private XmlSchemas schemas;
@@ -36,6 +40,7 @@ internal class DynamicWebServiceProxy
private ArrayList outParams = new ArrayList();
private ServiceCache serviceCache;
private readonly X509Certificate2 certificate;
+ private SoapVersion? version;
///
/// Creates a new instance.
@@ -44,12 +49,18 @@ internal class DynamicWebServiceProxy
/// Enables access to SOAP messages
/// Type of caching to be used
/// Certificate to use.
- internal DynamicWebServiceProxy(string wsdlLocation, bool enableMessageAccess = false, WsdlCache wsdlCache = WsdlCache.Both, X509Certificate2 certificate = null)
+ ///
+ internal DynamicWebServiceProxy(string wsdlLocation, bool enableMessageAccess = false, WsdlCache wsdlCache = WsdlCache.Both, X509Certificate2 certificate = null, SoapVersion? version = null)
{
this.wsdl = wsdlLocation;
this.enableMessageAccess = enableMessageAccess;
this.serviceCache = new ServiceCache(wsdlLocation, wsdlCache, new ServiceCache.CacheMissEvent(BuildAssemblyFromWsdl));
this.certificate = certificate;
+ this.version = version;
+ if (this.version == SoapVersion.SOAP_1_2)
+ protocolName = "Soap12";
+ else if (this.version == SoapVersion.SOAP_1_1)
+ protocolName = "Soap";
BuildProxy();
}
@@ -60,7 +71,7 @@ internal DynamicWebServiceProxy(string wsdlLocation, bool enableMessageAccess =
public object InvokeCall(string methodName ,PhpArray parameters)
{
var soapProxy = (SoapHttpClientProtocolExtended)proxyInstance;
- MethodInfo mi = soapProxy.GetType().GetMethod(methodName);
+ var mi = WsdlHelper.GetMethodBySoapName(methodName, soapProxy.GetType());
bool wrappedArgs = true;
@@ -79,13 +90,14 @@ public object InvokeCall(string methodName ,PhpArray parameters)
object[] transformedParameters = paramBinder.BindParams(mi, parameters, wrappedArgs);
- object[] resArray = soapProxy.Invoke(methodName, transformedParameters);
+ object[] resArray = soapProxy.Invoke(mi.Name, transformedParameters);
if (resArray[0] != null)
{
+ var returnName = WsdlHelper.GetParameterSoapName(mi.ReturnParameter);
resArray[0] = ResultBinder.BindResult(
resArray[0],
- mi.Name,
+ returnName,
wrappedArgs);
}
@@ -101,6 +113,7 @@ public object InvokeCall(string methodName ,PhpArray parameters)
return resArray[0];
}
+
#region Async invoke (not supported now)
/////
@@ -213,7 +226,7 @@ public string Wsdl
/// Gets or sets the name of the protocol.
///
///
- public Protocol ProtocolName
+ public Protocol? ProtocolName
{
get
{
@@ -225,6 +238,10 @@ public Protocol ProtocolName
return Protocol.HttpPost;
case "Soap":
return Protocol.HttpSoap;
+ case "Soap12":
+ return Protocol.HttpSoap12;
+ case null:
+ return null;
default:
return Protocol.HttpSoap;
}
@@ -242,6 +259,12 @@ public Protocol ProtocolName
case Protocol.HttpSoap:
protocolName = "Soap";
break;
+ case Protocol.HttpSoap12:
+ protocolName = "Soap12";
+ break;
+ case null:
+ protocolName = null;
+ break;
}
}
}
@@ -279,7 +302,9 @@ private Assembly BuildAssemblyFromWsdl(string absoluteWsdlLocation, string wsdlC
// WSDL service description importer
CodeNamespace cns = new CodeNamespace(CodeConstants.CODENAMESPACE);
+ CodeNamespace cnsServer = new CodeNamespace(CodeConstants.CODENAMESPACESERVER);//TODO: may be split assembly or merge namespaces
sdi = new ServiceDescriptionImporter();
+ sdi.CodeGenerationOptions = CodeGenerationOptions.None;
//sdi.AddServiceDescription(sd, null, null);
// check for optional imports in the root WSDL
@@ -287,10 +312,17 @@ private Assembly BuildAssemblyFromWsdl(string absoluteWsdlLocation, string wsdlC
sdi.ProtocolName = protocolName;
sdi.Import(cns, null);
+ sdi = new ServiceDescriptionImporter();
+ CheckForImports(absoluteWsdlLocation);
+ sdi.CodeGenerationOptions = CodeGenerationOptions.None;
+ sdi.ProtocolName = protocolName;
+ sdi.Style = ServiceDescriptionImportStyle.Server;
+ sdi.Import(cnsServer, null);
// change the base class
// get all available Service classes - not only the default one
ArrayList newCtr = new ArrayList();
+ Dictionary bodies = new Dictionary();
foreach (CodeTypeDeclaration ctDecl in cns.Types)
{
@@ -307,9 +339,40 @@ private Assembly BuildAssemblyFromWsdl(string absoluteWsdlLocation, string wsdlC
{
cns.Types.Remove(ctDecl);
ctDecl.BaseTypes[0] = new CodeTypeReference(CodeConstants.CUSTOMBASETYPE);
+ foreach (var member in ctDecl.Members.OfType())
+ {
+ bodies[member.Name] = member.Statements;
+ }
cns.Types.Add(ctDecl);
}
+ newCtr.Clear();
+ foreach (CodeTypeDeclaration ctDecl in cnsServer.Types)
+ {
+ if (ctDecl.BaseTypes.Count > 0)
+ {
+ if (ctDecl.BaseTypes[0].BaseType == CodeConstants.DEFAULTSERVERBASETYPE)
+ {
+ newCtr.Add(ctDecl);
+ }
+ }
+ }
+ foreach (CodeTypeDeclaration ctDecl in newCtr)
+ {
+ cnsServer.Types.Remove(ctDecl);
+ ctDecl.BaseTypes[0] = new CodeTypeReference(CodeConstants.CUSTOMSERVERBASETYPE);
+ ctDecl.TypeAttributes = ctDecl.TypeAttributes ^ TypeAttributes.Abstract;
+ foreach (var member in ctDecl.Members.OfType().Where(a=>(a.Attributes&MemberAttributes.ScopeMask)==MemberAttributes.Abstract).ToArray())
+ {
+ ctDecl.Members.Remove(member);
+ member.Attributes = member.Attributes ^ MemberAttributes.Abstract;
+ member.Statements.AddRange(bodies[member.Name]);
+ ctDecl.Members.Add(member);
+ }
+ cnsServer.Types.Add(ctDecl);
+ }
+
+
// source code generation
CSharpCodeProvider cscp = new CSharpCodeProvider();
StringBuilder srcStringBuilder = new StringBuilder();
@@ -332,8 +395,10 @@ private Assembly BuildAssemblyFromWsdl(string absoluteWsdlLocation, string wsdlC
}
}
}
-
- cscp.GenerateCodeFromNamespace(cns, sw, null);
+ var unit = new CodeCompileUnit();
+ unit.Namespaces.Add(cns);
+ unit.Namespaces.Add(cnsServer);
+ cscp.GenerateCodeFromCompileUnit(unit, sw, null);
proxySource = srcStringBuilder.ToString();
sw.Close();
@@ -402,7 +467,12 @@ private object CreateProxyInstance()
///
private void ResetInternalState()
{
- protocolName = "Soap";
+ if (version == null)
+ protocolName = null;
+ else if (version == SoapVersion.SOAP_1_2)
+ protocolName = "Soap12";
+ else
+ protocolName = "Soap";
sdi = null;
}
@@ -463,19 +533,18 @@ private void CheckForImports(string baseWSDLUrl)
/// Gets the SOAP request.
///
///
- public string SoapRequest
+ public PhpBytes SoapRequest
{
get
{
if (enableMessageAccess && pipelineProperlyConfigured)
{
- PropertyInfo propInfo = proxyInstance.GetType().GetProperty("SoapRequestString");
- object result = propInfo.GetValue(proxyInstance, null);
+ byte[] result = ((SoapHttpClientProtocolExtended)proxyInstance).SoapRequest;
- return (string)result;
+ return result == null ? PhpBytes.Empty : new PhpBytes(result);
}
else
- return String.Empty;
+ return PhpBytes.Empty;
}
}
@@ -483,19 +552,42 @@ public string SoapRequest
/// Gets the SOAP response.
///
///
- public string SoapResponse
+ public PhpBytes SoapResponse
{
get
{
if (enableMessageAccess && pipelineProperlyConfigured)
{
- PropertyInfo propInfo = proxyInstance.GetType().GetProperty("SoapResponseString");
- object result = propInfo.GetValue(proxyInstance, null);
+ byte[] result = ((SoapHttpClientProtocolExtended)proxyInstance).SoapResponse;
- return (string)result;
+ return result == null ? PhpBytes.Empty : new PhpBytes(result);
}
else
- return String.Empty;
+ return PhpBytes.Empty;
+ }
+ }
+
+ public string RequestHeaders
+ {
+ get
+ {
+ if (enableMessageAccess && pipelineProperlyConfigured)
+ {
+ return ((SoapHttpClientProtocolExtended) proxyInstance).RequestHeaders;
+ }
+ return string.Empty;
+ }
+ }
+
+ public string ResponseHeaders
+ {
+ get
+ {
+ if (enableMessageAccess && pipelineProperlyConfigured)
+ {
+ return ((SoapHttpClientProtocolExtended) proxyInstance).ResponseHeaders;
+ }
+ return string.Empty;
}
}
@@ -619,5 +711,19 @@ public ArrayList OutParameters
{
get { return outParams; }
}
+
+ public string Location
+ {
+ get
+ {
+ var soapProxy = (SoapHttpClientProtocolExtended)proxyInstance;
+ return soapProxy.Url;
+ }
+ set
+ {
+ var soapProxy = (SoapHttpClientProtocolExtended)proxyInstance;
+ soapProxy.Url = value;
+ }
+ }
}
}
diff --git a/Source/Extensions/Soap/Enums.cs b/Source/Extensions/Soap/Enums.cs
index 1870c0c3..31f82f61 100644
--- a/Source/Extensions/Soap/Enums.cs
+++ b/Source/Extensions/Soap/Enums.cs
@@ -44,6 +44,15 @@ internal enum Protocol
{
HttpGet,
HttpPost,
- HttpSoap
+ HttpSoap,
+ HttpSoap12
+ }
+
+ public enum SoapVersion
+ {
+ [ImplementsConstant("SOAP_1_1")]
+ SOAP_1_1 = 1,
+ [ImplementsConstant("SOAP_1_2")]
+ SOAP_1_2 = 2
}
}
diff --git a/Source/Extensions/Soap/Extension.Soap.csproj b/Source/Extensions/Soap/Extension.Soap.csproj
index 95ebcd64..7bea0cdb 100644
--- a/Source/Extensions/Soap/Extension.Soap.csproj
+++ b/Source/Extensions/Soap/Extension.Soap.csproj
@@ -68,6 +68,12 @@
+
+
+
+
+ Component
+
True
True
diff --git a/Source/Extensions/Soap/ParameterBinder.cs b/Source/Extensions/Soap/ParameterBinder.cs
index b25f706b..19f80c8c 100644
--- a/Source/Extensions/Soap/ParameterBinder.cs
+++ b/Source/Extensions/Soap/ParameterBinder.cs
@@ -6,6 +6,7 @@
using System.Collections;
using System.Reflection;
using PHP.Core.Reflection;
+using Convert = PHP.Core.Convert;
namespace PHP.Library.Soap
{
@@ -92,11 +93,15 @@ public object[] BindParams(MethodInfo mi, PhpArray parameters, bool wrappedArgs)
{
if (SetSpecifiedParameter(resultParams, pi))
continue;
-
- if (parameters.TryGetValue(pi.Name, out value))
+ value = null;
+ if (parameters == null || parameters.TryGetValue(pi.Name, out value))
{
resultParams.Add(Bind(value, pi.ParameterType));
}
+ else
+ {
+ resultParams.Add(pi.ParameterType.IsValueType ? Activator.CreateInstance(pi.ParameterType) : null);
+ }
}
}
@@ -113,11 +118,17 @@ public object[] BindParams(MethodInfo mi, PhpArray parameters, bool wrappedArgs)
private object Bind(object graph, Type targetType)
{
if (graph == null)
- return null;
+ {
+ if(!targetType.IsValueType)
+ return null;
+ return Activator.CreateInstance(targetType);
+ }
// unwrap Nullable<>
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
targetType = targetType.GetGenericArguments()[0];
+ if (targetType.IsByRef)
+ targetType = targetType.GetElementType();
switch (Type.GetTypeCode(graph.GetType()))
{
@@ -218,6 +229,9 @@ private object BindPrimitiveType(object obj, Type targetType)
if (targetType.IsValueType)
lastPrimitive = true;
+ if (targetType == typeof (string))
+ obj = Encoding.UTF8.GetString(Convert.ObjectToPhpBytes(obj).ReadonlyData);
+
return PHP.Core.ConvertToClr.ObjectToType(obj, targetType);
}
@@ -273,7 +287,10 @@ private object BindObject(DObject obj, Type targetType)
private object BindArray(PhpArray array, Type targetType)
{
if (targetType.IsArray)
+ {
+ array = (PhpArray) (array.ContainsKey("item") ? array["item"] : array); // TODO: ???
return BindArrayToArray(array, targetType);
+ }
else
return BindArrayToObject(array, targetType);
}
@@ -340,10 +357,12 @@ private object BindArrayToArray(PhpArray array, Type targetType)
{
Debug.Assert(targetType.IsArray);
+ var count = array == null ? 0 : array.Count;
+
Type elementType = targetType.GetElementType();
- Array vals = Array.CreateInstance(elementType, array.Count);
+ Array vals = Array.CreateInstance(elementType, count);
- for (int i = 0; i < array.Count; ++i)
+ for (int i = 0; i < count; ++i)
{
vals.SetValue(Bind(array[i], elementType), i);
}
@@ -355,5 +374,41 @@ private object BindArrayToArray(PhpArray array, Type targetType)
#endregion
+
+ public object[] BindServerResult(MethodInfo mi, PhpArray result, bool wrappedArgs)
+ {
+ var resultParams = new List();
+ var parameterInfos = new List();
+ parameterInfos.Add(mi.ReturnParameter);
+ parameterInfos.AddRange(mi.GetParameters().Where(a=>a.IsOut));
+ object value;
+
+
+ if (!wrappedArgs)
+ {
+ //TODO: make sure: When arguments are not wrapped soap method parameter is only one
+ Debug.Assert(parameterInfos.Count == 1);
+
+ resultParams.Add(Bind(result, parameterInfos[0].ParameterType));
+
+ }
+ else
+ {
+ foreach (var pi in parameterInfos)
+ {
+ if (SetSpecifiedParameter(resultParams, pi))
+ continue;
+ var name = WsdlHelper.GetParameterSoapName(pi);
+ if (result.TryGetValue(name, out value))
+ {
+ resultParams.Add(Bind(value, pi.ParameterType));
+ }
+ }
+ }
+
+ lastPrimitive = false;
+
+ return resultParams.ToArray();
+ }
}
}
diff --git a/Source/Extensions/Soap/ResultBinder.cs b/Source/Extensions/Soap/ResultBinder.cs
index 721d9541..35a2e4af 100644
--- a/Source/Extensions/Soap/ResultBinder.cs
+++ b/Source/Extensions/Soap/ResultBinder.cs
@@ -37,10 +37,27 @@ internal static object BindResult(object graph, string functionName, bool wrapRe
object res = Bind(graph);
if (wrapResult)
- return WrapToStdClass(res, functionName + "Result");
+ return WrapToStdClass(res, functionName);
else
return res;
}
+
+ internal static object BindServerParameters(object[] parameters, MethodInfo mi)
+ {
+ var runtimeFields = new PhpArray();
+ //I can also just return CLR type and wrap it with PHP.Core.Reflection.ClrObject.WrapDynamic
+ int i = 0;
+ foreach (var p in mi.GetParameters().Where(a => !a.IsOut))
+ {
+ var name = WsdlHelper.GetParameterSoapName(p);
+ var value = Bind(parameters[i++]);
+ runtimeFields[name] = value;
+ }
+ return new stdClass()
+ {
+ RuntimeFields = runtimeFields
+ };
+ }
private static object BindEnum(object obj, Type type)
{
@@ -75,9 +92,18 @@ private static object BindObject(object obj, Type type)
if (specified)
{
- value = Bind(field.GetValue(obj), field);
+ var fieldValue = field.GetValue(obj);
+ value = Bind(fieldValue, field);
if (value != null)
- runtimeFields.Add(field.Name, value);
+ {
+ if (fieldValue != null && fieldValue.GetType().IsArray && ((Array) fieldValue).Length > 0)
+ fieldValue = ((Array) fieldValue).GetValue(0);
+ var attr = Attribute.GetCustomAttributes(field, typeof(XmlElementAttribute)).Cast().FirstOrDefault(a => a.Type == null || a.Type.IsInstanceOfType(fieldValue));
+ var name = field.Name;
+ if (attr != null && !string.IsNullOrWhiteSpace(attr.ElementName))
+ name = attr.ElementName;
+ runtimeFields.Add(name, value);
+ }
}
}
@@ -92,29 +118,28 @@ private static string GetArrayItemTypeName(Type type, FieldInfo fi)
if (fi == null)
return "item";
- object[] attr = fi.GetCustomAttributes(false);
+ XmlArrayItemAttribute[] attr = (XmlArrayItemAttribute[])fi.GetCustomAttributes(typeof(XmlArrayItemAttribute), false);
for (int i = 0; i < attr.Length; ++i)
{
- if (attr[i].GetType() == typeof(XmlArrayItemAttribute))
- {
- XmlArrayItemAttribute arrayItemAttr = (XmlArrayItemAttribute)attr[i];
- if (!String.IsNullOrEmpty(arrayItemAttr.ElementName))
- return arrayItemAttr.ElementName;
- else
- return type.GetElementType().Name;
- }
- else if (attr[i].GetType() == typeof(XmlArrayAttribute))
- {
+ XmlArrayItemAttribute arrayItemAttr = (XmlArrayItemAttribute) attr[i];
+ if (!String.IsNullOrEmpty(arrayItemAttr.ElementName))
+ return arrayItemAttr.ElementName;
+ else
return type.GetElementType().Name;
- }
}
+ XmlArrayAttribute attr1 = (XmlArrayAttribute)fi.GetCustomAttribute(typeof(XmlArrayAttribute), false);
+ if (attr1 != null)
+ return type.GetElementType().Name;
return null;
}
private static object BindArray(object obj, Type type, FieldInfo targetFieldInfo)
{
+ if (type == typeof(byte[]))
+ return new PhpBytes((byte[])obj);
+
Array array = (Array)obj;
object res;
string elementName;
@@ -176,8 +201,8 @@ private static object Bind(object graph, FieldInfo targetFieldInfo = null)
if (type.IsEnum)
return BindEnum(graph, type);
-
-
+ if (type == typeof (string))
+ graph = Encoding.Default.GetString(Encoding.UTF8.GetBytes((string) graph));
return PHP.Core.Convert.ClrLiteralToPhpLiteral(graph);
case TypeCode.DateTime:
@@ -187,7 +212,7 @@ private static object Bind(object graph, FieldInfo targetFieldInfo = null)
if (dt.TimeOfDay == TimeSpan.Zero)
return dt.ToString("yyyy-MM-dd");
- return dt.ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz");
+ return dt.ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz");
case TypeCode.Object:
{
diff --git a/Source/Extensions/Soap/SoapClient.cs b/Source/Extensions/Soap/SoapClient.cs
index b8a8238e..29412812 100644
--- a/Source/Extensions/Soap/SoapClient.cs
+++ b/Source/Extensions/Soap/SoapClient.cs
@@ -20,6 +20,13 @@ public partial class SoapClient : PhpObject
{
private DynamicWebServiceProxy wsp = null;
private bool exceptions = true;
+ private SoapVersion version = SoapVersion.SOAP_1_1;
+
+ [PhpVisible, ImplementsMethod]
+ public object __soapCall(string function_name, PhpArray arguments)
+ {
+ return __call(function_name, arguments);
+ }
///
/// Calls a SOAP function
@@ -33,9 +40,9 @@ public object __call(string function_name, PhpArray arguments/*, PhpArray option
{
var item = arguments.GetArrayItem(0, true);
- if (item != null && item.GetType() == typeof(PhpArray))
+ if ((item != null && item.GetType() == typeof (PhpArray)) || item == null)
{
- PhpArray arr = (PhpArray)item;
+ PhpArray arr = (PhpArray) item;
return wsp.InvokeCall(function_name, arr);
}
}
@@ -75,7 +82,7 @@ public PhpArray __getFunctions()
/// Returns last SOAP request
///
[PhpVisible, ImplementsMethod]
- public string __getLastRequest()
+ public PhpBytes __getLastRequest()
{
try
{
@@ -95,8 +102,15 @@ public string __getLastRequest()
[PhpVisible, ImplementsMethod]
public string __getLastRequestHeaders()
{
- PhpException.FunctionNotSupported(PhpError.Warning);
- return null;
+ try
+ {
+ return wsp.RequestHeaders;
+ }
+ catch (Exception exception)
+ {
+ SoapFault.Throw(ScriptContext.CurrentContext, "SOAP-ERROR", exception.Message, exceptions);
+ return null;
+ }
}
@@ -104,7 +118,7 @@ public string __getLastRequestHeaders()
/// Returns last SOAP response
///
[PhpVisible, ImplementsMethod]
- public object __getLastResponse()
+ public PhpBytes __getLastResponse()
{
try
{
@@ -124,8 +138,15 @@ public object __getLastResponse()
[PhpVisible, ImplementsMethod]
public string __getLastResponseHeaders()
{
- PhpException.FunctionNotSupported(PhpError.Warning);
- return null;
+ try
+ {
+ return wsp.ResponseHeaders;
+ }
+ catch (Exception exception)
+ {
+ SoapFault.Throw(ScriptContext.CurrentContext, "SOAP-ERROR", exception.Message, exceptions);
+ return null;
+ }
}
@@ -157,8 +178,9 @@ public void __setCookie(string name, string value)
[PhpVisible, ImplementsMethod]
public string __setLocation(string new_location)
{
- PhpException.FunctionNotSupported(PhpError.Warning);
- return null;
+ var result = wsp.Location;
+ wsp.Location = new_location;
+ return result;
}
@@ -217,6 +239,11 @@ public void __construct(string wsdl, [Optional] PhpArray options)
exceptions = PHP.Core.Convert.ObjectToBoolean(value);
}
+ if (options.TryGetValue("soap_version", out value))
+ {
+ version = (SoapVersion) PHP.Core.Convert.ObjectToInteger(value);
+ }
+
// certificate:
string pass = null;
@@ -229,13 +256,13 @@ public void __construct(string wsdl, [Optional] PhpArray options)
{
var cert = Core.Convert.ObjectToString(value);
if (cert != null)
- certificate = new X509Certificate2(cert, pass);
+ certificate = new X509Certificate2(cert, pass, X509KeyStorageFlags.MachineKeySet);
}
}
try
{
- wsp = new DynamicWebServiceProxy(wsdl, enableMessageAccess, wsdlCache, certificate);
+ wsp = new DynamicWebServiceProxy(wsdl, enableMessageAccess, wsdlCache, certificate, version);
}
catch (Exception exception)
{
diff --git a/Source/Extensions/Soap/SoapClient.dynamic.cs b/Source/Extensions/Soap/SoapClient.dynamic.cs
index 95251671..62ea3e82 100644
--- a/Source/Extensions/Soap/SoapClient.dynamic.cs
+++ b/Source/Extensions/Soap/SoapClient.dynamic.cs
@@ -9,27 +9,57 @@
using System.Text;
using PHP.Core;
using System.Runtime.InteropServices;
+using System.Security.Cryptography.X509Certificates;
+using System.IO;
namespace PHP.Library.Soap
{
[Serializable()]
public partial class SoapClient
{
- ///
protected SoapClient(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context)
{
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public SoapClient(ScriptContext context, bool newInstance) : base(context, newInstance)
{
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public SoapClient(ScriptContext context, DTypeDesc caller) : this(context, true)
{
this.InvokeConstructor(context, caller);
}
- ///
+ [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
+ public object __soapCall(ScriptContext __context, object function_name, object arguments)
+ {
+
+ string tmp1 = PhpVariable.AsString(function_name);
+ if (tmp1 == null)
+
+ {
+ PhpException.InvalidImplicitCast(function_name, "string", "__soapCall");
+ return null;
+ }
+
+ PhpArray tmp2 = arguments as PhpArray;
+ if (tmp2 == null)
+
+ {
+ PhpException.InvalidImplicitCast(arguments, "PhpArray", "__soapCall");
+ return null;
+ }
+ return __soapCall(tmp1, tmp2);
+ }
+ [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
+ public static object __soapCall(object instance, PhpStack stack)
+ {
+ stack.CalleeName = "__soapCall";
+
+ object arg1 = stack.PeekValue(1);
+
+ object arg2 = stack.PeekValue(2);
+ stack.RemoveFrame();
+ return ((SoapClient)instance).__soapCall(stack.Context, arg1, arg2);
+ }
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public object __call(ScriptContext __context, object function_name, object arguments)
{
@@ -51,7 +81,6 @@ public object __call(ScriptContext __context, object function_name, object argum
}
return __call(tmp1, tmp2);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static object __call(object instance, PhpStack stack)
{
@@ -63,13 +92,11 @@ public static object __call(object instance, PhpStack stack)
stack.RemoveFrame();
return ((SoapClient)instance).__call(stack.Context, arg1, arg2);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public object __doRequest(ScriptContext __context)
{
return __doRequest();
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static object __doRequest(object instance, PhpStack stack)
{
@@ -77,13 +104,11 @@ public static object __doRequest(object instance, PhpStack stack)
stack.RemoveFrame();
return ((SoapClient)instance).__doRequest(stack.Context);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public object __getFunctions(ScriptContext __context)
{
return __getFunctions();
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static object __getFunctions(object instance, PhpStack stack)
{
@@ -91,13 +116,11 @@ public static object __getFunctions(object instance, PhpStack stack)
stack.RemoveFrame();
return ((SoapClient)instance).__getFunctions(stack.Context);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public object __getLastRequest(ScriptContext __context)
{
return __getLastRequest();
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static object __getLastRequest(object instance, PhpStack stack)
{
@@ -105,13 +128,11 @@ public static object __getLastRequest(object instance, PhpStack stack)
stack.RemoveFrame();
return ((SoapClient)instance).__getLastRequest(stack.Context);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public object __getLastRequestHeaders(ScriptContext __context)
{
return __getLastRequestHeaders();
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static object __getLastRequestHeaders(object instance, PhpStack stack)
{
@@ -119,13 +140,11 @@ public static object __getLastRequestHeaders(object instance, PhpStack stack)
stack.RemoveFrame();
return ((SoapClient)instance).__getLastRequestHeaders(stack.Context);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public object __getLastResponse(ScriptContext __context)
{
return __getLastResponse();
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static object __getLastResponse(object instance, PhpStack stack)
{
@@ -133,13 +152,11 @@ public static object __getLastResponse(object instance, PhpStack stack)
stack.RemoveFrame();
return ((SoapClient)instance).__getLastResponse(stack.Context);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public object __getLastResponseHeaders(ScriptContext __context)
{
return __getLastResponseHeaders();
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static object __getLastResponseHeaders(object instance, PhpStack stack)
{
@@ -147,13 +164,11 @@ public static object __getLastResponseHeaders(object instance, PhpStack stack)
stack.RemoveFrame();
return ((SoapClient)instance).__getLastResponseHeaders(stack.Context);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public object __getTypes(ScriptContext __context)
{
return __getTypes();
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static object __getTypes(object instance, PhpStack stack)
{
@@ -161,7 +176,6 @@ public static object __getTypes(object instance, PhpStack stack)
stack.RemoveFrame();
return ((SoapClient)instance).__getTypes(stack.Context);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public object __setCookie(ScriptContext __context, object name, object value)
{
@@ -184,7 +198,6 @@ public object __setCookie(ScriptContext __context, object name, object value)
__setCookie(tmp1, tmp2);
return null;
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static object __setCookie(object instance, PhpStack stack)
{
@@ -196,7 +209,6 @@ public static object __setCookie(object instance, PhpStack stack)
stack.RemoveFrame();
return ((SoapClient)instance).__setCookie(stack.Context, arg1, arg2);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public object __setLocation(ScriptContext __context, object new_location)
{
@@ -210,7 +222,6 @@ public object __setLocation(ScriptContext __context, object new_location)
}
return __setLocation(tmp1);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static object __setLocation(object instance, PhpStack stack)
{
@@ -220,7 +231,6 @@ public static object __setLocation(object instance, PhpStack stack)
stack.RemoveFrame();
return ((SoapClient)instance).__setLocation(stack.Context, arg1);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public object __setSoapHeaders(ScriptContext __context, object SoapHeaders)
{
@@ -235,7 +245,6 @@ public object __setSoapHeaders(ScriptContext __context, object SoapHeaders)
__setSoapHeaders(tmp1);
return null;
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static object __setSoapHeaders(object instance, PhpStack stack)
{
@@ -245,7 +254,6 @@ public static object __setSoapHeaders(object instance, PhpStack stack)
stack.RemoveFrame();
return ((SoapClient)instance).__setSoapHeaders(stack.Context, arg1);
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public object __construct(ScriptContext __context, object wsdl, [System.Runtime.InteropServices.OptionalAttribute()]
object options)
@@ -274,7 +282,6 @@ public static object __setSoapHeaders(object instance, PhpStack stack)
__construct(tmp1, tmp2);
return null;
}
- ///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static object __construct(object instance, PhpStack stack)
{
@@ -286,9 +293,9 @@ public static object __construct(object instance, PhpStack stack)
stack.RemoveFrame();
return ((SoapClient)instance).__construct(stack.Context, arg1, arg2);
}
- ///
private static void __PopulateTypeDesc(PhpTypeDesc desc)
{
+ desc.AddMethod("__soapCall", PhpMemberAttributes.Public, new RoutineDelegate(SoapClient.__soapCall));
desc.AddMethod("__call", PhpMemberAttributes.Public, new RoutineDelegate(SoapClient.__call));
desc.AddMethod("__doRequest", PhpMemberAttributes.Public, new RoutineDelegate(SoapClient.__doRequest));
desc.AddMethod("__getFunctions", PhpMemberAttributes.Public, new RoutineDelegate(SoapClient.__getFunctions));
diff --git a/Source/Extensions/Soap/SoapHttpClientProtocolExtended.cs b/Source/Extensions/Soap/SoapHttpClientProtocolExtended.cs
index cebac89f..c48fd111 100644
--- a/Source/Extensions/Soap/SoapHttpClientProtocolExtended.cs
+++ b/Source/Extensions/Soap/SoapHttpClientProtocolExtended.cs
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Net;
using System.Text;
+using System.Web;
using System.Web.Services.Protocols;
namespace PHP.Library.Soap
@@ -14,6 +16,8 @@ public class SoapHttpClientProtocolExtended : SoapHttpClientProtocol
{
private byte[] m_SoapRequestMsg;
private byte[] m_SoapResponseMsg;
+ private WebRequest lastRequest;
+ private WebResponse lastResponse;
///
/// Creates a new instance.
@@ -110,5 +114,39 @@ public new object[] Invoke(string methodName, object[] parameters)
{
return base.Invoke(methodName, parameters);
}
+
+ protected override WebRequest GetWebRequest(Uri uri)
+ {
+ return lastRequest = base.GetWebRequest(uri);
+ }
+
+ protected override WebResponse GetWebResponse(WebRequest request)
+ {
+ return lastResponse = base.GetWebResponse(request);
+ }
+
+ public string RequestHeaders
+ {
+ get
+ {
+ var req = (HttpWebRequest) lastRequest;
+ var sb = new StringBuilder();
+ sb.AppendFormat("{0} {1} HTTP/{2}{3}", req.Method, req.RequestUri.PathAndQuery, req.ProtocolVersion.ToString(2), Environment.NewLine);
+ sb.Append(req.Headers);
+ return sb.ToString();
+ }
+ }
+
+ public string ResponseHeaders
+ {
+ get
+ {
+ var res = ((HttpWebResponse) lastResponse);
+ var sb = new StringBuilder();
+ sb.AppendFormat("HTTP/{0} {1} {2}{3}", res.ProtocolVersion.ToString(2), (int)res.StatusCode, res.StatusDescription, Environment.NewLine);
+ sb.Append(res.Headers);
+ return sb.ToString();
+ }
+ }
}
}
diff --git a/Source/Extensions/Soap/SoapMessageAccessClientExtension.cs b/Source/Extensions/Soap/SoapMessageAccessClientExtension.cs
index 08c0bb8f..4adf68d7 100644
--- a/Source/Extensions/Soap/SoapMessageAccessClientExtension.cs
+++ b/Source/Extensions/Soap/SoapMessageAccessClientExtension.cs
@@ -198,7 +198,12 @@ protected virtual void Dispose(bool disposing)
// Set large fields to null
if (oldStream != null)
{
- oldStream.Close();
+ try
+ {
+ oldStream.Close();
+ }
+ catch(InvalidOperationException)
+ {}
oldStream = null;
}
diff --git a/Source/Extensions/Soap/SoapServer.cs b/Source/Extensions/Soap/SoapServer.cs
new file mode 100644
index 00000000..c15aa630
--- /dev/null
+++ b/Source/Extensions/Soap/SoapServer.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Web;
+using System.Web.Services.Protocols;
+using PHP.Core;
+using PHP.Core.Reflection;
+
+namespace PHP.Library.Soap
+{
+ [ImplementsType()]
+ public partial class SoapServer : PhpObject
+ {
+ private DynamicWebServiceProxy wsp;
+ private DTypeDesc type;
+
+ public SoapServer(string wsdl) : this(wsdl, null)
+ {
+ }
+
+ public SoapServer(string wsdl, PhpArray options) : base(ScriptContext.CurrentContext, true)
+ {
+
+ }
+
+ [PhpVisible, ImplementsMethod]
+ public void __construct(string wsdl, [Optional] PhpArray options)
+ {
+ wsp = new DynamicWebServiceProxy(wsdl);
+ }
+
+ [PhpVisible, ImplementsMethod]
+ public void setClass(string class_name)
+ {
+ var context = ScriptContext.CurrentContext;
+ type = context.DeclaredTypes[class_name];
+ }
+
+ private static MethodInfo coreGetHandler = typeof(WebServiceHandlerFactory).GetMethod("CoreGetHandler",
+ BindingFlags.NonPublic | BindingFlags.Instance);
+ [PhpVisible, ImplementsMethod]
+ public void handle()
+ {
+ var clrType = wsp.ProxyAssembly.GetTypes().First(a => a.BaseType == typeof (WebServiceExtended));
+ var factory = new WebServiceHandlerFactory();
+ var context = HttpContext.Current;
+ context.Items["SoapServerType"] = type;
+ context.Items["SoapServerDynamicWebServiceProxy"] = wsp;
+ var handler = (IHttpHandler) coreGetHandler.Invoke(factory, new object[] {clrType, context, context.Request, context.Response});
+ handler.ProcessRequest(context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/Extensions/Soap/WebServiceExtended.cs b/Source/Extensions/Soap/WebServiceExtended.cs
new file mode 100644
index 00000000..b435ba7e
--- /dev/null
+++ b/Source/Extensions/Soap/WebServiceExtended.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web.Services;
+using PHP.Core;
+using PHP.Core.Reflection;
+using Convert = PHP.Core.Convert;
+
+namespace PHP.Library.Soap
+{
+ public class WebServiceExtended : WebService
+ {
+ protected object[] Invoke(string name, params object[] parameters)
+ {
+ var type = (DTypeDesc) Context.Items["SoapServerType"];
+ var method = type.GetMethod(new Name(name));
+ var clrMethod = WsdlHelper.GetMethodBySoapName(name, GetType());
+ var p = ResultBinder.BindServerParameters(parameters, clrMethod);
+ var context = ScriptContext.CurrentContext;
+ context.Stack.AddFrame(p);
+ var result = Convert.ObjectToPhpArray(method.Invoke(null, context.Stack));
+ var binder = new ParameterBinder();
+ var results = binder.BindServerResult(clrMethod, result, true);
+ return results;
+ }
+ }
+}
diff --git a/Source/Extensions/Soap/WsdlHelper.cs b/Source/Extensions/Soap/WsdlHelper.cs
index dd03f427..b45b3e55 100644
--- a/Source/Extensions/Soap/WsdlHelper.cs
+++ b/Source/Extensions/Soap/WsdlHelper.cs
@@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reflection;
using System.Text;
using System.IO;
using System.Net;
+using System.Web.Services.Protocols;
+using System.Xml.Serialization;
using PHP.Core;
namespace PHP.Library.Soap
@@ -38,5 +41,31 @@ internal static string GetWsdlContent(string source, out string fullPath)
return wsdlSourceValue;
}
+ internal static MethodInfo GetMethodBySoapName(string methodName, Type type)
+ {
+ MethodInfo mi = type.GetMethod(methodName);
+ if (mi == null)
+ {
+ foreach (var methodInfo in type.GetMethods())
+ {
+ var at = (SoapDocumentMethodAttribute)methodInfo.GetCustomAttributes(typeof(SoapDocumentMethodAttribute)).SingleOrDefault();
+ if (at != null && at.RequestElementName == methodName)
+ {
+ mi = methodInfo;
+ break;
+ }
+ }
+ }
+ return mi;
+ }
+
+ internal static string GetParameterSoapName(ParameterInfo parameter)
+ {
+ var name = parameter.Name ?? parameter.Member.Name + "Result";
+ var at = (XmlElementAttribute)parameter.GetCustomAttribute(typeof(XmlElementAttribute));
+ if (at != null && !string.IsNullOrWhiteSpace(at.ElementName))
+ name = at.ElementName;
+ return name;
+ }
}
}
diff --git a/Source/Extensions/Xml/PhpXmlParser.cs b/Source/Extensions/Xml/PhpXmlParser.cs
index 738095f9..2ea01e0a 100644
--- a/Source/Extensions/Xml/PhpXmlParser.cs
+++ b/Source/Extensions/Xml/PhpXmlParser.cs
@@ -369,7 +369,7 @@ public static int Parse(NamingContext/*!*/ namingContext, DTypeDesc caller, PhpR
/// with operators such as ===.
///
[ImplementsFunction("xml_parse_into_struct", FunctionImplOptions.NeedsClassContext | FunctionImplOptions.NeedsNamingContext)]
- public static int ParseIntoStruct(NamingContext/*!*/ namingContext, DTypeDesc caller, PhpResource parser, string data, PhpReference values)
+ public static int ParseIntoStruct(NamingContext/*!*/ namingContext, DTypeDesc caller, PhpResource parser, object data, PhpReference values)
{
return ParseIntoStruct(namingContext, caller, parser, data, values, null);
}
@@ -392,7 +392,7 @@ public static int ParseIntoStruct(NamingContext/*!*/ namingContext, DTypeDesc ca
/// with operators such as ===.
///
[ImplementsFunction("xml_parse_into_struct", FunctionImplOptions.NeedsClassContext | FunctionImplOptions.NeedsNamingContext)]
- public static int ParseIntoStruct(NamingContext/*!*/ namingContext, DTypeDesc caller, PhpResource parser, string data, PhpReference values, PhpReference index)
+ public static int ParseIntoStruct(NamingContext/*!*/ namingContext, DTypeDesc caller, PhpResource parser, object data, PhpReference values, PhpReference index)
{
if (values == null)
{
diff --git a/Source/Extensions/Xml/XmlParserResource.cs b/Source/Extensions/Xml/XmlParserResource.cs
index 67caf270..0f8a3109 100644
--- a/Source/Extensions/Xml/XmlParserResource.cs
+++ b/Source/Extensions/Xml/XmlParserResource.cs
@@ -6,6 +6,7 @@
using System.Xml;
using System.IO;
using PHP.Core.Reflection;
+using Convert = PHP.Core.Convert;
namespace PHP.Library.Xml
{
@@ -223,15 +224,25 @@ public bool Parse(DTypeDesc caller, NamingContext context, string input, bool is
}
}
- public bool ParseIntoStruct(DTypeDesc caller, NamingContext context, string input, PhpArray values, PhpArray indices)
+ public bool ParseIntoStruct(DTypeDesc caller, NamingContext context, object input, PhpArray values, PhpArray indices)
{
return ParseInternal(caller, context, input, values, indices);
}
- private bool ParseInternal(DTypeDesc caller, NamingContext context, string xml, PhpArray values, PhpArray indices)
+ private bool ParseInternal(DTypeDesc caller, NamingContext context, object xml, PhpArray values, PhpArray indices)
{
- StringReader stringReader = new StringReader(xml);
- XmlTextReader reader = new XmlTextReader(stringReader);
+ Stream stream;
+ PhpBytes phpBytes;
+ byte[] bytes;
+ if ((phpBytes = xml as PhpBytes) != null)
+ stream = new MemoryStream(phpBytes.ReadonlyData, false);
+ else if ((bytes = xml as byte[]) != null)
+ stream = new MemoryStream(bytes);
+ else
+ stream = new RecodingStream(Convert.ObjectToString(xml), Configuration.Application.Globalization.PageEncoding);
+ XmlTextReader reader = new XmlTextReader(stream);
+ reader.DtdProcessing = DtdProcessing.Ignore;
+
Stack elementStack = new Stack();
TextRecord textChunk = null;
@@ -242,6 +253,7 @@ private bool ParseInternal(DTypeDesc caller, NamingContext context, string xml,
_endNamespaceDeclHandler.BindOrBiteMyLegsOff(caller, context);
_characterDataHandler.BindOrBiteMyLegsOff(caller, context);
_processingInstructionHandler.BindOrBiteMyLegsOff(caller, context);
+ int depth = 1;
while (reader.ReadState == ReadState.Initial || reader.ReadState == ReadState.Interactive)
{
@@ -282,7 +294,7 @@ private bool ParseInternal(DTypeDesc caller, NamingContext context, string xml,
case ReadState.Interactive:
//debug step, that prints out the current state of the parser (pretty printed)
//Debug_ParseStep(reader);
- ParseStep(reader, elementStack, ref textChunk, values, indices);
+ ParseStep(reader, elementStack, ref textChunk, values, indices, ref depth);
break;
}
@@ -293,7 +305,7 @@ private bool ParseInternal(DTypeDesc caller, NamingContext context, string xml,
return true;
}
- private void ParseStep(XmlReader reader, Stack elementStack, ref TextRecord textChunk, PhpArray values, PhpArray indices)
+ private void ParseStep(XmlTextReader reader, Stack elementStack, ref TextRecord textChunk, PhpArray values, PhpArray indices, ref int depth)
{
string elementName;
bool emptyElement;
@@ -302,7 +314,7 @@ private void ParseStep(XmlReader reader, Stack elementStack, ref
switch (reader.NodeType)
{
case XmlNodeType.Element:
- elementName = reader.Name;
+ elementName = _enableCaseFolding ? reader.Name.ToUpperInvariant() : reader.Name;
emptyElement = reader.IsEmptyElement;
PhpArray attributeArray = new PhpArray();
@@ -326,8 +338,7 @@ private void ParseStep(XmlReader reader, Stack elementStack, ref
continue;
}
-
- attributeArray.Add(_enableCaseFolding ? reader.Name.ToUpperInvariant() : reader.Name, reader.Value);
+ attributeArray.Add(_enableCaseFolding ? reader.Name.ToUpperInvariant() : reader.Name, new PhpBytes(reader.Encoding.GetBytes(reader.Value)));
}
while (reader.MoveToNextAttribute());
}
@@ -337,7 +348,7 @@ private void ParseStep(XmlReader reader, Stack elementStack, ref
{
currentElementRecord = elementStack.Peek();
- UpdateValueAndIndexArrays(currentElementRecord, ref textChunk, values, indices, true);
+ UpdateValueAndIndexArrays(reader, currentElementRecord, ref textChunk, values, indices, true);
if (currentElementRecord.State == ElementState.Beginning)
currentElementRecord.State = ElementState.Interior;
@@ -347,10 +358,12 @@ private void ParseStep(XmlReader reader, Stack elementStack, ref
elementStack.Push(
new ElementRecord() {
ElementName = elementName,
- Level = reader.Depth,
+ Level = depth,
State = ElementState.Beginning,
Attributes = (PhpArray)attributeArray.DeepCopy()
});
+ if (!reader.IsEmptyElement)
+ depth++;
if (_startElementHandler.Callback != null)
_startElementHandler.Invoke(this, _enableCaseFolding ? elementName.ToUpperInvariant() : elementName, attributeArray);
@@ -374,12 +387,14 @@ private void ParseStep(XmlReader reader, Stack elementStack, ref
// pop the top element record
currentElementRecord = elementStack.Pop();
- UpdateValueAndIndexArrays(currentElementRecord, ref textChunk, values, indices, false);
+ UpdateValueAndIndexArrays(reader, currentElementRecord, ref textChunk, values, indices, false);
if (_endElementHandler.Callback != null)
_endElementHandler.Invoke(this, _enableCaseFolding ? elementName.ToUpperInvariant() : elementName);
else
if (_defaultHandler.Callback != null) _defaultHandler.Invoke(this, "");
+ if (!reader.IsEmptyElement)
+ depth--;
break;
@@ -411,51 +426,55 @@ private void ParseStep(XmlReader reader, Stack elementStack, ref
}
}
- private void UpdateValueAndIndexArrays(ElementRecord elementRecord, ref TextRecord textRecord, PhpArray values, PhpArray indices, bool middle)
+ private void UpdateValueAndIndexArrays(XmlTextReader reader, ElementRecord elementRecord, ref TextRecord textRecord, PhpArray values, PhpArray indices, bool middle)
{
- // if we have no valid data in the middle, just end
- if (middle && textRecord == null)
- return;
-
- if (!middle && elementRecord.State == ElementState.Interior)
- UpdateValueAndIndexArrays(elementRecord, ref textRecord, values, indices, true);
-
if (values != null)
{
PhpArray arrayRecord = new PhpArray();
arrayRecord.Add("tag", elementRecord.ElementName);
- arrayRecord.Add("level", elementRecord.Level);
if (elementRecord.State == ElementState.Beginning)
arrayRecord.Add("type", middle ? "open" : "complete");
else
arrayRecord.Add("type", middle ? "cdata" : "close");
+ arrayRecord.Add("level", elementRecord.Level);
- if (textRecord != null)
- arrayRecord.Add("value", textRecord.Text);
+ if (textRecord != null && !string.IsNullOrWhiteSpace(textRecord.Text))
+ arrayRecord.Add("value", new PhpBytes(reader.Encoding.GetBytes(textRecord.Text)));
- if (elementRecord.State == ElementState.Beginning && elementRecord.Attributes.Count != 0)
- arrayRecord.Add("attributes", elementRecord.Attributes);
+ if ((string)arrayRecord["type"] != "cdata" || arrayRecord.ContainsKey("value"))
+ {
- values.Add(arrayRecord);
+ if (elementRecord.State == ElementState.Beginning && elementRecord.Attributes.Count != 0)
+ arrayRecord.Add("attributes", elementRecord.Attributes);
- if (indices != null)
- {
- PhpArray elementIndices;
+ values.Add(arrayRecord);
- if (!indices.ContainsKey(elementRecord.ElementName))
+ if (indices != null)
{
- elementIndices = new PhpArray();
- indices.Add(elementRecord.ElementName, elementIndices);
- }
- else
- elementIndices = (PhpArray)indices[elementRecord.ElementName];
+ PhpArray elementIndices;
- // add the max index (last inserted value)
- elementIndices.Add(values.MaxIntegerKey);
+ if (!indices.ContainsKey(elementRecord.ElementName))
+ {
+ elementIndices = new PhpArray();
+ indices.Add(elementRecord.ElementName, elementIndices);
+ }
+ else
+ elementIndices = (PhpArray) indices[elementRecord.ElementName];
+
+ // add the max index (last inserted value)
+ elementIndices.Add(values.MaxIntegerKey);
+ }
}
}
+ // if we have no valid data in the middle, just end
+ if (middle && textRecord == null)
+ return;
+
+ if (!middle && elementRecord.State == ElementState.Interior)
+ UpdateValueAndIndexArrays(reader, elementRecord, ref textRecord, values, indices, true);
+
textRecord = null;
}
@@ -477,5 +496,76 @@ public XmlParserResource(Encoding outputEncoding, bool processNamespaces, string
_enableCaseFolding = true;
_enableSkipWhitespace = false;
}
+
+ private class RecodingStream : Stream
+ {
+ private char[] data;
+ private Encoder encoder;
+ private int charsPosition;
+
+ public RecodingStream(string data, Encoding encoding)
+ {
+ this.data = data.ToCharArray();
+ encoder = encoding.GetEncoder();
+ }
+
+ public override void Flush()
+ {
+ encoder.Reset();
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (charsPosition >= data.Length)
+ return 0;
+ int charsUsed;
+ int bytesUsed;
+ bool completed;
+ encoder.Convert(data, charsPosition, data.Length - charsPosition, buffer, offset, count, false, out charsUsed, out bytesUsed, out completed);
+ charsPosition += charsUsed;
+ return bytesUsed;
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override bool CanRead
+ {
+ get { return true; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return false; }
+ }
+
+ public override long Length
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+ }
}
}
diff --git a/Source/Extensions/Zlib/PhpZlib.cs b/Source/Extensions/Zlib/PhpZlib.cs
index 227713f0..301c1290 100644
--- a/Source/Extensions/Zlib/PhpZlib.cs
+++ b/Source/Extensions/Zlib/PhpZlib.cs
@@ -155,6 +155,7 @@ public static PhpBytes GzCompress(PhpBytes data, int level)
PhpException.Throw(PhpError.Warning, String.Format("compression level ({0}) must be within -1..9", level));
return null;
}
+ if (data == null) data = PhpBytes.Empty;
int length_bound = data.Length + (data.Length / PHP_ZLIB_MODIFIER) + 15 + 1;
diff --git a/Source/Extensions/iconv/PhpNetIconv.cs b/Source/Extensions/iconv/PhpNetIconv.cs
index d649df52..549cf532 100644
--- a/Source/Extensions/iconv/PhpNetIconv.cs
+++ b/Source/Extensions/iconv/PhpNetIconv.cs
@@ -364,6 +364,7 @@ public static object iconv_substr(object/*string*/str, int offset, int length /*
[return: CastToFalse]
public static PhpBytes iconv(string in_charset, string out_charset, object str)
{
+ PhpBytes result = null;
// check args
if (str == null)
{
@@ -400,46 +401,48 @@ public static PhpBytes iconv(string in_charset, string out_charset, object str)
else
out_encoding.EncoderFallback = new StopEncoderFallback(out_result); // throw notice and discard all remaining characters
- try
+ //
+ var in_encoding = ResolveEncoding(in_charset);
+ if (in_encoding == null)
+ {
+ PhpException.Throw(PhpError.Notice, string.Format(Strings.wrong_charset, in_charset, in_charset, out_charset));
+ result = null;
+ }
+ else if (str.GetType() == typeof(PhpBytes))
{
- //
- if (str.GetType() == typeof(PhpBytes))
+ // resolve in_charset
+ if (in_charset == null)
+ {
+ PhpException.ArgumentNull("in_charset");
+ result = null;
+ }
+ else
{
- // resolve in_charset
- if (in_charset == null)
- {
- PhpException.ArgumentNull("in_charset");
- return null;
- }
- var in_encoding = ResolveEncoding(in_charset);
- if (in_encoding == null)
- {
- PhpException.Throw(PhpError.Notice, string.Format(Strings.wrong_charset, in_charset, in_charset, out_charset));
- return null;
- }
-
// TODO: in_encoding.Clone() ensures it is NOT readOnly, then set DecoderFallback to catch invalid byte sequences
// convert to
- return new PhpBytes(out_encoding.GetBytes(in_encoding.GetString(((PhpBytes)str).ReadonlyData)));
- }
-
- if (str.GetType() == typeof(string) || (str = Core.Convert.ObjectToString(str)) != null)
- {
- // convert UTF16 to
- return new PhpBytes(out_encoding.GetBytes((string)str));
+ result = new PhpBytes(out_encoding.GetBytes(in_encoding.GetString(((PhpBytes) str).ReadonlyData)));
}
}
- finally
+ else if (str.GetType() == typeof(string) || (str = Core.Convert.ObjectToString(str)) != null)
{
- if (out_result.firstFallbackCharIndex >= 0)
+ // convert UTF16 to
+ var pageEncoding = Configuration.Application.Globalization.PageEncoding;
+ if (in_encoding.Equals(pageEncoding))
+ result = new PhpBytes(out_encoding.GetBytes((string) str));
+ else
+ result = new PhpBytes(Encoding.Convert(in_encoding, out_encoding, pageEncoding.GetBytes((string)str)));
+ }
+ if (out_result.firstFallbackCharIndex >= 0)
+ {
+ // Notice: iconv(): Detected an illegal character in input string
+ PHP.Core.PhpException.Throw(Core.PhpError.Notice, Strings.illegal_character);
+ if (!transliterate && !discard_ilseq)
{
- // Notice: iconv(): Detected an illegal character in input string
- PHP.Core.PhpException.Throw(Core.PhpError.Notice, Strings.illegal_character);
+ result = null;
}
}
-
- return null;
+ return result;
}
//ob_iconv_handler — Convert character encoding as output buffer handler
diff --git a/Source/Extensions/mbstring/MbString.cs b/Source/Extensions/mbstring/MbString.cs
index edb9e014..e64411ea 100644
--- a/Source/Extensions/mbstring/MbString.cs
+++ b/Source/Extensions/mbstring/MbString.cs
@@ -173,7 +173,11 @@ public enum CaseConstants
// .NET encodings
foreach (var encoding in Encoding.GetEncodings())
- enc[encoding.Name] = encoding.GetEncoding();
+ {
+ var e = encoding.GetEncoding();
+ enc[encoding.Name] = e;
+ enc["cp" + encoding.CodePage] = e;
+ }
_encodings = enc;
}