Skip to content
This repository has been archived by the owner on Oct 23, 2019. It is now read-only.

a lot of bugfixes #19

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions Source/ClassLibrary/FileSystem.CLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,9 @@ public static bool IsFile(string path)
{
StreamWrapper wrapper;

if (path.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this causes cloning of the array :-( maybe clone it for the first time into some private static property, and use that so we avoid cloning every time?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return false;

if (StatInternalCheck(ref path, false, out wrapper))
{
string url;
Expand Down
4 changes: 2 additions & 2 deletions Source/ClassLibrary/Web.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/// <summary>
Expand All @@ -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)
Expand Down
44 changes: 40 additions & 4 deletions Source/Core/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,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()
};
}
}

Expand Down Expand Up @@ -337,7 +344,23 @@ private static string AbsolutizeLogFile(string value, System.Xml.XmlNode/*!*/nod
/// </summary>
internal ErrorControlSection DeepCopy()
{
return (ErrorControlSection)this.MemberwiseClone();
return new ErrorControlSection()
{
DisplayErrors = DisplayErrors,
DocRefExtension = DocRefExtension,
DocRefRoot = DocRefRoot,
EnableLogging = EnableLogging,
ErrorAppendString = ErrorAppendString,
ErrorPrependString = ErrorPrependString,
HtmlMessages = HtmlMessages,
IgnoreAtOperator = IgnoreAtOperator,
LogFile = LogFile,
ReportErrors = ReportErrors,
SysLog = SysLog,
UserExceptionHandler = UserExceptionHandler == null ? null : UserExceptionHandler.DeepCopy(),
UserHandler = UserHandler == null ? null : UserHandler.DeepCopy(),
UserHandlerErrors = UserHandlerErrors
};
}
}

Expand Down Expand Up @@ -422,7 +445,14 @@ public sealed partial class AssertionSection : IPhpConfigurationSection
/// </summary>
internal AssertionSection DeepCopy()
{
return (AssertionSection)this.MemberwiseClone();
return new AssertionSection()
{
Active = Active,
Callback = Callback == null ? null : Callback.DeepCopy(),
Quiet = Quiet,
ReportWarning = ReportWarning,
Terminate = Terminate
};
}
}

Expand Down Expand Up @@ -503,7 +533,13 @@ public static bool ValidateRegisteringOrder(string value)
/// </summary>
internal VariablesSection DeepCopy()
{
return (VariablesSection)this.MemberwiseClone();
return new VariablesSection()
{
AlwaysPopulateRawPostData = AlwaysPopulateRawPostData,
DeserializationCallback = DeserializationCallback == null ? null : DeserializationCallback.DeepCopy(),
QuoteRuntimeVariables = QuoteRuntimeVariables,
RegisteringOrder = RegisteringOrder
};
}
}

Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Errors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ public static void ArgumentNull(string argument)
/// <param name="argument">The name of the argument.</param>
public static void ReferenceNull(string argument)
{
Throw(PhpError.Error, CoreResources.GetString("reference_null", argument));
Throw(PhpError.Warning, CoreResources.GetString("reference_null", argument));
}

/// <summary>
Expand Down Expand Up @@ -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 && !context.ErrorReportingDisabled;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOT CORRECT, revert this line please.
User error handler IS called if reporting is disabled.

Example:

function myErrorHandler($errno, $errstr, $errfile, $errline){echo __FUNCTION__;}
set_error_handler("myErrorHandler");

$x = 0;
echo @(12 / $x);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked on php and user handler not called. what version of php are you using?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

php 5.5.3

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i checked behavior on sample from http://www.php.net/manual/en/function.set-error-handler.php and not noticed that user handler checks error reporting status :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

bool is_error_fatal = ((PhpErrorSet)error & PhpErrorSet.Fatal) != 0;
bool do_report = true;

Expand Down
21 changes: 1 addition & 20 deletions Source/Core/PhpBytes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,24 +203,7 @@ 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);
}
}
output.Write(ToString());
}

private string DebugView()
Expand Down Expand Up @@ -421,9 +404,7 @@ string IPhpConvertible.ToString(bool throwOnError, out bool success)
/// <param name="output">The output text stream.</param>
public void Print(System.IO.TextWriter output)
{
output.Write("\"");
DumpTo(output);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

print != dump

Print should output this.ToString()
Dump should output binary with the string escaped

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

output.WriteLine("\"");
}

/// <summary>
Expand Down
7 changes: 6 additions & 1 deletion Source/Core/PhpCallback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,12 @@ string IPhpConvertible.ToString()
}
}

/// <summary>
public PhpCallback DeepCopy()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PhpCallback can be MemberwiseCopied, but do not copy this on another thread; on another thread callback has to be re-bound

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method called only on unbounded Callbacks

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add Debug.Assert at least please

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

{
return (PhpCallback)MemberwiseClone();
}

/// <summary>
/// Converts instance to its string representation according to PHP conversion algorithm.
/// </summary>
/// <param name="success">Indicates whether conversion was successful.</param>
Expand Down
11 changes: 8 additions & 3 deletions Source/Core/ScriptContext.CLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -337,21 +337,26 @@ public static ScriptContext CurrentContext
// ScriptContext is ILogicalThreadAffinative, LogicalCallContext is used.
try
{
return ((ScriptContext)CallContext.GetData(callContextSlotName)) ?? CreateDefaultScriptContext(); // on Mono, .GetData must be used (GetLogicalData is not implemented)
var weak = (WeakReference<ScriptContext>)CallContext.GetData(callContextSlotName);// on Mono, .GetData must be used (GetLogicalData is not implemented)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REVERT

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if revert this line then ScriptContext can be leaked after calling async code directly or indirectly (for instance: HttpWebRequest.ServicePoint) and survived context can keep in memory up to several MB. At least cleanup on dispose

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScriptContext.CurrentContext is nullified at RequestEnd

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScriptContext.CurrentContext on current thread is nullifed, but after calling, for example, HttpWebRequest.ServicePoint, reference to this ScriptContext will be in other thread CallContext.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you must never use an instance of ScriptContext on another thread, without wrapping it into
using (var context = ScriptContext.Init***) // or ScriptContext.Fork
{ ... }

Once you get an instance of ScriptContext on a thread, you are responsible for cleaning it up.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thats because ScriptContext is not thread safe, and it should not live outside of a RequestContext

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its not used in another thread its just copied to another thread by .net (with all other call context data)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't see why. Anyway CallContext won't be used within the next update at all. There would be just [ThreadStatic] field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ScriptContext survived because one callback (from global configuration) used for all ScriptContexts
1
This ScriptContext survived because thread call context contains reference to it
2
Because .net copied call context data to another thread
3

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

ScriptContext result = null;
if (weak!=null)
{
weak.TryGetTarget(out result);
}
return result ?? CreateDefaultScriptContext();
}
catch (InvalidCastException)
{
throw new InvalidCallContextDataException(callContextSlotName);
}

//return result.AttachToHttpApplication();
}
set
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REVERT

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

{
if (value == null)
CallContext.FreeNamedDataSlot(callContextSlotName);
else
CallContext.SetData(callContextSlotName, value); // on Mono, .SetData must be used (SetLogicalData is not implemented)
CallContext.SetData(callContextSlotName, new WeakReference<ScriptContext>(value)); // on Mono, .SetData must be used (SetLogicalData is not implemented)
}
}

Expand Down
13 changes: 13 additions & 0 deletions Source/Extensions/Curl/CurlHttp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -95,6 +96,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

Expand Down
3 changes: 2 additions & 1 deletion Source/Extensions/Curl/HttpFormDataUploader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.IO;
using System.Threading;
using System.Security;
using Convert = PHP.Core.Convert;

namespace PHP.Library.Curl
{
Expand Down Expand Up @@ -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();
Expand Down
11 changes: 8 additions & 3 deletions Source/Extensions/Curl/UserDefined.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -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

Expand Down
53 changes: 44 additions & 9 deletions Source/Extensions/Gd2/PhpGd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -714,12 +714,24 @@ public static bool imagecolormatch(PhpResource im1, PhpResource im2)
/// <summary>
/// Get the index of the specified color or its closest possible alternative
/// </summary>
[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
Expand Down Expand Up @@ -758,11 +770,26 @@ public static void imagecolorset(PhpResource im, int col, int red, int green, in
/// <summary>
/// Get the colors for an index
/// </summary>
[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
Expand Down Expand Up @@ -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;
}

/// <summary>
Expand Down
3 changes: 3 additions & 0 deletions Source/Extensions/Soap/CodeConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down