I have a problem, and I can not solve it for several days.
My simple code (dll file):
public static string RegisterUser(string table, string l, string p)
{
string query = "INSERT INTO " + table + "(login, password) VALUES ('" + l + "','" + p + "');";
return query;
}
Everything works fine, but when I want to write the data received on the network, it does not return the full string, for example
string recieveStr = Encoding.UTF8.GetString(connection.Buffer); //received text: RegUser:nipercop:passwrd
string[] strArr = recieveStr.Split(':');
if (strArr[0].Equals("RegUser"))
{
// string p = strArr[2]; //passwrd
// sendStr = SqlCommands.RegisterUser("users",strArr[1], "passwrd");//works fine
sendStr = SqlCommands.RegisterUser("users",strArr[1], strArr[2]); // doesn't work
}
returns message like that:
INSERT INTO users(mail, password) VALUES ('nipercop','passwrd
Lost end of the string " ') ". No errors, no warnings, no anything.
I tried change encoding to ASCII on server, on client, but no effect.
Try using string.Format:
string.Format(#"INSERT INTO {0}(login, password) VALUES ('{1}','{2}');", table, l, p);
Though ideally you should be using prepared SQL statements. The reason being is any of the values you insert could contain unexpected values, which leaves your code vulnerable to SQL injection and a plethora of other bad things.
For example if strArr[2] would contain " here, it'd cut off the query and result in an error. As it stands, your code doesn't account for that while seemingly accepting input from a remote socket. That's something you may want to revise.
The problem is was reading strings from the buffer.
Encoding.UTF8.GetString(connection.Buffer,0 , bufferLength);
Because the buffer length was (for example) 1024 bytes, and my last variable was length of the remainder of the length of the other variables, ie contained a empty symbols (spaces). Fail.
Related
I am writing Insurance Managment System as project at University.
This is my MySQL commadn:
string lifeQuery = "insert into lifeinsurance values( null, '" + surname.Text + "." + pesel.Text + "', " + double.Parse(lifeInsSumTB.Text) + ", '" + double.Parse(lifeInsPriceTB.Text)
+ ");";
But te problem is that in UWP double is with ',' and to MySQL i need to have it with '.'.
When I try to do this like this: '25,453' it says data truncated. Without ' ', like this 25,453 it says that column count doesn't match value count at row 1, because it interets it as two different values 25 and 453.
So my question is:
How do I insert this double value to my table?
This problem is caused by the implicit conversion to a string when you call double.Parse and then concatenate the result back into the sql text. This requires the compiler to represent the double value as a string and it will use the current culture to do the conversion. Of course the result is not what MySql expect to be a double value.
Moreover using string concatenation to build sql commands leads to Sql Injection hacks. A very nasty problem that you should avoid. Always.
So let's try to add some code to resolve these problems
// A parameterized string without any concatenation from user input
string lifeQuery = #"insert into lifeinsurance
values( null, #surname, #sum, #price)";
MySqlCommand cmd = new MySqlCommand(lifeQuery, connection);
// Add the parameters with value for each placeholder in string
cmd.Parameters.AddWithValue("#surname", surname.Text + "." + pesel.Text);
// Parse the user input as a double using the current culture to correctly
// interpret the comma as decimal separator.
// Note that here I have no check on the correctness of the input. If your
// user cannot be trusted to type a valid double number then you should use
// the double.TryParse approach separating these lines from the actual check
cmd.Parameters.AddWithValue("#sum", double.Parse(lifeInsSumTB.Text, CultureInfo.CurrentCulture));
cmd.Parameters.AddWithValue("#price", double.Parse(lifeInsPriceTB.Text, CultureInfo.CurrentCulture));
cmd.ExecuteNonQuery();
Like other said - there are better ways to send over data with Sql. That being said this answer focuses on addressing your specific problem.
I think your problem may be your language/culture settings.
Try this:
Console.WriteLine(double.Parse("19.2323244").ToString("G", CultureInfo.InvariantCulture));
Output:
19.2323244
https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo?view=netcore-3.1#Invariant
When I insert in DB a string that contains special character as a "à" or a "é" from a FileInfo.GetFiles() item, I get issues and SQL save splitted special char. Non-special chars are OK.
For instance, "à" becomes "a`", and "é" becomes "e´". Did anyone get this kind of trouble?
Here is the code
DirectoryInfo di = new DirectoryInfo(path);
foreach (FileInfo fi in di.GetFiles())
{
Logger.LogInfo("Info: " + fi.Name);
}
Basically, if string is "sàrl", log saved "Info: sa`rl"
When I breakpoint trough VS, I see the string with "à" but when I log it, char are splitted.
My SQL collation is Latin CI AS (SQL_Latin1_General_CP1_CI_AS) and DB already host string with special char without problem.
Thanks folks
EDIT
I have trouble when I insert the fi.Name into the final table too:
public bool InsertFile(string fileName, Societe company, string remark, PersonnelAM creator)
{
string commandText = (#"INSERT INTO [dbo].[TB_DOCSOCIETE_COM] " +
"([IdtSOC] " +
",[NomDOC] " +
",[RemDOC] " +
",[DateDOC] " +
",[IdtPER]) " +
"VALUES " +
"(#company" +
",#fileName" +
",#remark" +
",#date" +
",#creator) SELECT ##IDENTITY");
var identity = CreateCommand(commandText,
new SqlParameter("#fileName", DAOHelper.HandleNullValueAndMinDateTime<string>(fileName)),
new SqlParameter("#company", DAOHelper.HandleNullValueAndMinDateTime<int>(company.Id)),
new SqlParameter("#remark", DAOHelper.HandleNullValueAndMinDateTime<string>(remark)),
new SqlParameter("#date", DAOHelper.HandleNullValueAndMinDateTime<DateTime>(DateTime.Now)),
new SqlParameter("#creator", DAOHelper.HandleNullValueAndMinDateTime<int>(creator.id))
).ExecuteScalar();
return int.Parse(identity.ToString()) > 0;
}
I'm using NLog so data is varchar(8000) for message column and code that logs message is
public static bool LogInfo(Exception ex, string message = "")
{
try
{
GetLogger().Log(LogLevel.Info, ex, message);
}
#pragma warning disable 0168
catch (Exception exception)
#pragma warning restore 0168
{
return false;
}
return true;
}
EDIT 2 :
To be clear about DB, those 3 lines:
Logger.LogInfo("BL1 " + "sàrl is right saved");
Logger.LogInfo("BL2 " + fi.Name + " is not right saved");
Logger.LogInfo("BL3 " + "sàrl" + " - " + fi.Name + " is not right too!");
Gave me that result in DB:
BL1 sàrl is right saved
BL2 ENTERPRISE Sa`rl - file.pdf is not right saved
BL3 sàrl - ENTERPRISE Sa`rl - file.pdf is not right too!
So it doesn't come from DB, it is an issue about the string (encoding?)
varchar(8000)
Make the column NVARCHAR. This is not a collation issue. Collations determine the sort order and comparison rules, not the storage. Is true that for non-unicode columns (varchar) the collation is used as hint to determine the code page of the result. But code page will only get you so far, as obviously a 1 byte encoding code page cannot match the entire space of the file system naming, which is 2 bytes encoding Unicode based.
Use an Unicode column: NVARCHAR.
If you want to understand what are you experiencing, just run this:
declare #a nvarchar(4000) = NCHAR(0x00E0) + N'a' + NCHAR(0x0300)
select #a, cast(#a as varchar);
Unicode is full of wonderful surprises, like Combining characters. You can't distinguish them visually, but they sure show up when you look at the actual encoded bytes.
I have grabbed some data from a website.A string which is named as urlresult in the data is "http:\/\/www.cnopyright.com.cn\/index.php?com=com_noticeQuery&method=wareList&optionid=1221&obligee=\u5317\u4eac\u6c83\u534e\u521b\u65b0\u79d1\u6280\u6709\u9650\u516c\u53f8&softwareType=1".
what I want to do is to get rid of the first three char #'\' in the string urlresult above . I have tried the function below:
public string ConvertDataToUrl(string urlresult )
{
var url= urlresult.Split('?')[0].Replace(#"\", "") + "?" + urlresult .Split('?')[1];
return url
}
It returns "http://www.cnopyright.com.cn/index.php?com=com_noticeQuery&method=wareList&optionid=1221&obligee=\\u5317\\u4eac\\u6c83\\u534e\\u521b\\u65b0\\u79d1\\u6280\\u6709\\u9650\\u516c\\u53f8&softwareType=1" which is incorrect.
The correct result is "http://www.cnopyright.com.cn/index.php?com=com_noticeQuery&method=wareList&optionid=1221&obligee=北京沃华创新科技有限公司&softwareType=1"
I have tried many ways,but it hasn't worked.I have no idea how to get the correct result.
I think you may be misled by the debugger because there's no reason that extra "\" characters should get inserted by the code you provided. Often times the debugger will show extra "\" in a quoted string so that you can tell which "\" characters are really there versus which are there to represent other special characters. I would suggest writing the string out with Debug.WriteLine or putting it in a log file. I don't think the information you provided in the question is correct.
As proof of this, I compiled and ran this code:
static void Main(string[] args)
{
var url = #"http:\/\/www.cnopyright.com.cn\/index.php?com=com_noticeQuery&method=wareList&optionid=1221&obligee=\u5317\u4eac\u6c83\u534e\u521b\u65b0\u79d1\u6280\u6709\u9650\u516c\u53f8&softwareType=1";
Console.WriteLine("{0}{1}{2}", url, Environment.NewLine,
url.Split('?')[0].Replace(#"\", "") + "?" + url.Split('?')[1]);
}
The output is:
http:\/\/www.cnopyright.com.cn\/index.php?com=com_noticeQuery&method=wareList&optionid=1221&obligee=\u5317\u4eac\u6c83\u534e\u521b\u65b0\u79d1\u6280\u6709\u9650\u516c\u53f8&softwareType=1
http://www.cnopyright.com.cn/index.php?com=com_noticeQuery&method=wareList&optionid=1221&obligee=\u5317\u4eac\u6c83\u534e\u521b\u65b0\u79d1\u6280\u6709\u9650\u516c\u53f8&softwareType=1
You can use the System.Text.RegularExpressions.Regex.Unescape method:
var input = #"\u5317\u4eac\u6c83\u534e\u521b\u65b0\u79d1\u6280\u6709\u9650\u516c\u53f8";
string escapedText = System.Text.RegularExpressions.Regex.Unescape(input);
I'm getting a weird issue with substringing. Apparently the string I get can't be cast into an Int32 for some odd reason. The error message I get when I try doing that is "input string is not in correct format". Because of this, I can't insert these values into the Database either.
Here's the code...
string width = GetMetadata(filename, 162); //returns "1280 pixels"
string height = GetMetadata(filename, 164); //returns "700 pixels"
width = width.Substring(0, width.IndexOf(' ')); //returns "1280"
height = height.Substring(0, height.IndexOf(' ')); //returns "700"
//test: "System.Convert.ToInt32(width)" will fail, giving error "input string was not in correct format"
//doing the above on "width" yields the same result
//fails, giving error "no such column: 1280" (underlying database is sqlite)
Database.NonQuery("INSERT INTO image VALUES (" + fileid + ", " + width + ", " + height + ")");
For all the normal reasons - primarily avoiding leaving data conversions to the database, and preventing SQL injection attacks - I would suggest that you perform the parsing to a number in C#, and then use a parameterized query to talk to SQLite.
In this case, that will make it a lot easier to debug - either .NET will fail to parse the string as well (in which case it's likely to be a problem with your data) or it will work, and you won't need to worry about what conversions database was performing.
EDIT: I've just seen your comment saying that Convert.ToInt32 fails as well. That's a pretty clear indication that it's the data which is causing a problem.
I'd expect your code to look something like this:
string widthText = GetMetadata(filename, 162);
string heightText = GetMetadata(filename, 164);
widthText = width.Substring(0, width.IndexOf(' ')).Trim();
heightText = height.Substring(0, height.IndexOf(' ')).Trim();
int width = int.Parse(widthText, CulutureInfo.InvariantCulture);
int height = int.Parse(widthText, CulutureInfo.InvariantCulture);
using (SQLiteCommand cmd = Database.CreateCommand())
{
cmd.CommandText = "INSERT INTO image VALUES (?, ?, ?)";
cmd.Parameters.Add(fileid);
cmd.Parameters.Add(width);
cmd.Parameters.Add(height);
cmd.ExecuteNonQuery();
}
Note that the Trim call will remove any leading spaces, which it seems was the cause of the problem.
There may be some stray whitespaces in the string variables width and height. Invoke Trim() method on the strings before casting them into integers:
width = width.Trim();
height = height.Trim();
Hope this helps. Let us know.
I know we should never do this:
string select = "SELECT * FROM table1 ";
string where = "WHERE Name = '" + name + "' ";
string sql = select + where;
//execute the sql via ADO.NET
because of sql injection, because name can contain the char ', because of another 100 reasons. But now I have to do something similiar. I have a Dictionary<string, object> whose data look like:
Key(string) Value(object)
"Name" "Bob" //string
"ID" 10092L //long
"Birthday" 1980-05-07 00:00:00 //DateTime
"Salary" 5000.5m //decimal
//some others, whose key is a string, and value is string/long/int/DateTime/decimal
I want an easy way, to get all items in the dictionary collected in a String, just like a where statement:
Name = 'Bob' and ID = 10092 and Birthday = '1980-05-07 00:00:00' and Salary = 5000.5
String and DateTime are quoted with ', but note that the Name can be O'Neal. Is there any easy implementation? Input the dictionary, and return the string as a result.
EDIT Note that what I want is the string, I'm not going to execute it, parameterized command doesn't help. I just want a string that looks like a perfect safe WHERE statement.
The first code is only a problem if name is something entered by the user. Otherwise, it should be fine.
I don't know that it eliminates all problems but you might try experimenting with something like name = name.Replace("'", "''"). By converting all single quotes to double single quotes, you prevent the type of problems you described. Another approach might be to remove any single quotes.
However, the best route is to use query arguments. ADO supports these nicely and that would also eliminate any possibility of injection attacks.
The easy way could be like this:
string results = string.Join(" and ", myDict.Select( x=> x.Key + " = " + x.Value));
This of course wouldn't solve the quotes ' issue depending on different datatypes so you cannot use this as input to a SQL query - for that I would strongly recommend named parameters anyway - but is otherwise correct depending on the ToString() implementation of the values in your dictionary.
I wrote this many years ago, and always use it, and never ever have to think about this again. it is a waste of brain cells to solve this more than once:
// replace things like:
// O'Keefe with
// 'O''Keefe'
// make sure you don't call this twice!
static public string SqlString(string strInputSQL)
{
string strOut;
strOut = strInputSQL;
strOut = strOut.Replace ("'", "''");
strOut = "'" + strOut + "'";
return strOut;
}
Use it like this:
string sql = "SELECT * FROM FOO WHERE Name LIKE " + SqlString(myvalue);
There may be a dozen other ways to do it, but if you can have one and only one function, and use it consistently, you will save alot of time.
Try this link : Creating safe SQL statements as Strings
Some people consider this over-engineered, or just labourious to type. I fall back on a simple argument though...
Someone has already invested time and effort ensuring arguements can be safely and reliably included in SQL statements. Are you 100% certain you have pre-empted every possible scenario? Or is it more likely tried and tested code is more reliable?
But, then, I'm a bit anal ;)
var sb = new StringBuilder();
var isFirst = true;
foreach (var element in dic)
{
if(!isFirst)
sb.Append(" AND ");
else
isFirst = false;
sb.Append(element.Key);
sb.Append(" = ");
if(element.Value is decimal)
sb.Append(CastToSqlDecimalString((decimal)element.Value));
else
sb.Append("'" + String.Format(CultureInfo.InvariantCulture, "{0:G}", element.Value).Replace("'", "''") + "'");
}
You might want to handle decimals using this function
public static string CastToSqlDecimalString(decimal dec)
{
var sqlDecimal = new System.Data.SqlTypes.SqlDecimal(dec);
return string.Format("CAST({0} AS DECIMAL({1}, {2}))",
string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:G}", dec),
sqlDecimal.Precision,
sqlDecimal.Scale);
}