I’m trying to convert some code to use PHP’s odbc_prepare and odbc_execute to insert the data into a SQL Server table using parameters for security but I can't get past errors due to the way PHP handles single quotes in parameters and SQL Server's need for single quotes around text to be cast to datetime.
I have a web form that accepts a datetime from the user amongst other data.
The output from the datetime input box (missdt below) is in the format YY-MM-DDTHH:MM:SS (e.g. 2019-10-09T10:14:00)
Here’s my code (shortened for this post, yes I clean up the post data in my real code):
$missdt = $_POST["missdt"]; // results in 2019-10-09T10:14:00 stored as datetime in SQL Server
$branch = intval($_POST["branch"]); // stored as integer in SQL Server
$name = $_POST["name"]; // stored as varchar in SQL Server
$params = array($branch,
$missdt, // results in SQL error “Invalid character value for cast specification”
$name, );
$sql = "insert into my_table (branch, submitted, miss_date, name)
values (?, getdate(), ?, ?) ";
$res = odbc_prepare($conn, $sql);
$stmt = odbc_execute($res, $params);
The problem is that the $missdt parameter results in a SQL error “Invalid character value for cast specification”
I’ve tried the following variations for $missdt in the $params array and received the indicated errors:
"'" . $missdt . "'", // (added quotes) PHP error can't open file
"' " . $missdt . " '", // (added quotes and spaces) PHP error can't open file
"'" . $missdt . "' ", // (space after) SQL error Invalid character value for cast specification
'"' . $missdt . '"', // (double quotes used with set quoted_identifier off) results in “invalid parameter number” & “odbc_execute() expects parameter 1 to be resource”
This variation on the sql query works fine but could be abused:
$sql = "insert into my_table (branch, submitted, miss_date, name) values (?, getdate(), ‘$missdt’, ?) ";
According to the PHP documentation using single quotes before and after a parameter results in the parameter being treated as a filename and a workaround is to add a space to the beginning or end of the parameter. You can see from the variations I’ve tried above that doesn’t work in this case. I think this is because SQL Server needs the quotes in order to cast the character data to datetime.
Any ideas on how to get around this?
I’m using PHP 7.1, SQL Server 2014, and Apache on Windows 2012
So it turns out it wasn't the single quotes causing the problem. It was the "T" in the date-time input. If I use str_replace and replace the T with a space, the sql using the parameter without quotes works correctly.
for example:
$missdt = str_replace('T', ' ',$_POST["missdt"] );
then
$sql = "insert into my_table (branch, submitted, miss_date, name)
values (?, getdate(), ?, ?) ";
works just fine.
I have moved to IIS 8 in PHP 5.4. I am trying to collect data from a table and insert them to a different one, i know my code is correct, but seems to be not working, probably because of the php version, can anyone help me?
here's my code
$query = odbc_exec($conn, "SELECT * FROM member");
while($rows = odbc_fetch_array($query)) {
$querystring = "INSERT INTO oldusers (username, password, regdate) VALUES ('$rows['userid']', '$rows['passwd']', '$rows['registdate']')";
$query2 = odbc_exec($conn, $querystring);
odbc_free_result($query2);
//echo $rows['userid']." ".$rows['passwd']." ".$rows['registdate']."<br>";
}
thanks in advance.
instead trying to insert one by one record, better to insert like below:
INSERT INTO oldusers (username, password, regdate) SELECT userid,passwd,registdate FROM member
for more information :http://dev.mysql.com/doc/refman/5.5/en/insert-select.html
You're placing $rows['passwd'] inside of a double-quoted string. Instead you should do:
$str = "some sql $rows[passwd] rest of sql"; // notice the absence of single quotes
or:
$str = "some sql {$rows['passwd']} rest of sql";
or (I think this way is most readable):
$str = 'some sql' . $rows[passwd] . ' rest of sql';
If your column contains text you'll need to add surrounding single quotes where necessary.
Having said all that, you should instead use parameterized queries (if your database supports it) as it's safer (from SQL injection). If that's unavailable you will at the very least need to escape the data before concatenating it to the string.
i'm having trouble with the code below. it's been simplified to show the problem. i use a loop because the input names are identical and need to create multiple new rows in a mysql table. the problem is i'm using $_POST['name'][$i] and the table won't accept because it doesn't see it as 'text?, ...i think.
like i said, code's been greatly simplified.
for($i=0;$i<count($_POST['url']); $i++) {
$sql = 'INSERT INTO urls (url) VALUES ('. $_POST['url'][$i].')';
if(!mysql_query($sql)) {
echo "error " . mysql_error();
}
}
i tried to rememdy with this -
$sql = 'INSERT INTO urls (url) VALUES ('. '"'. $_POST['url'][$i].'"'. ')';
if i do this it works, there is no error
$sql = 'INSERT INTO urls (url) VALUES (' " hello " ')';
this is probably a newbie type mistake, right? thanks for any help with this.
A cleaner way (and the errors are fixed):
$urls = (isset($_POST['url']) && is_array($_POST['url'])) ? $_POST['url'] : array();
foreach($urls as $url) {
if(!is_string($url)) {
continue;
}
$sql = "INSERT INTO urls (url) VALUES ('" . mysql_real_escape_string($url) . "')";
if(!mysql_query($sql)) {
echo "error " . mysql_error();
}
}
Making sure the $_POST['url'] is an array will keep from trying to treat a non array (or non-existent key) as an array. The is_string is to protect from a user trying to throw in a sub array to get PHP to throw a "using array as string" notice. The escape is to avoid SQL injection, and the single quotes added are so MySQL knows it's a string.
You simply need to add quotes around the POSTed value in your MySQL query like below. Also, if you don't escape the input, it's a massive SQL injection vulnerability:
$data = mysql_escape_string($_POST['url'][$i]);
$sql = 'INSERT INTO urls (url) VALUES ("'.$data.'")';
The query breaks MySQL because MySQL thinks your post value is supposed to be numeric without the quotes.
It would be helpful to see that actual error message returned by mysql_error() but I think your problem is that you're not providing the $_POST value to the sql query as thought it's text.
try replacing
$sql = 'INSERT INTO urls (url) VALUES ('. $_POST['url'][$i].')';
with
$sql = "INSERT INTO urls (url) VALUES ('". mysql_real_escape_string($_POST['url'][$i]) ."')";
You need to escape your $_POST variables before you insert them via an SQL statement, preferably using the mysql_real_escape_string() function to fortify your query against SQL injection attacks.
Answer provided by Corbin is good - however try not to fire insert queries in a loop.
You could create the sql query as one string and then fire the insert query once.
You could change your insert statement from
insert into table (field) values(1);
insert into table (field) values(1);
To:
insert into table (field) values(1), (2), (3), (4)...
This is a more optimal solution - however mysql has a max length to which it can take sql statements - therefore use your best judgement.
try this statement
$sql = "INSERT INTO urls (url) VALUES ('". mysql_real_escape_string($_POST['url'][$i])."')";
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 9 years ago.
I am getting this error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 's','portal','','offering','MSNBC','News','','sports','','MSN','Money','','games'' at line 3
The only problem is that this error shows up when inserting data that contains an apostrophe. I tried changing the data type from VARCHAR to TEXT, but the result is still the same.
I tried to put in addslashes()
How do I fix this?
$query=" INSERT INTO alltags
(id,tag1,tag2,tag3,tag4,tag5,tag6,tag7,tag8,tag9,tag10,tag11,tag12,tag13,tag14,tag15,tag16,tag17,tag18,tag19,tag20,tag21,tag22,tag23,tag24,tag25,tag26,tag27,tag28,tag29,tag30)
VALUES
('',mysql_real_escape_string($uniqkey[0]),mysql_real_escape_string($uniqkey[1]),mysql_real_escape_string($uniqkey[2]),mysql_real_escape_string($uniqkey[3]),mysql_real_escape_string($uniqkey[4]),mysql_real_escape_string($uniqkey[5]),mysql_real_escape_string($uniqkey[6]),mysql_real_escape_string($uniqkey[7]),mysql_real_escape_string($uniqkey[8]),mysql_real_escape_string($uniqkey[9]),mysql_real_escape_string($uniqkey[10]),mysql_real_escape_string($uniqkey[11]),mysql_real_escape_string($uniqkey[12]),mysql_real_escape_string($uniqkey[13]),mysql_real_escape_string($uniqkey[14]),mysql_real_escape_string($uniqkey[15]),mysql_real_escape_string($uniqkey[16]),mysql_real_escape_string($uniqkey[17]),mysql_real_escape_string($uniqkey[18]),mysql_real_escape_string($uniqkey[19]),mysql_real_escape_string($uniqkey[20]),mysql_real_escape_string($uniqkey[21]),mysql_real_escape_string($uniqkey[22]),mysql_real_escape_string($uniqkey[23]),mysql_real_escape_string($uniqkey[24]),mysql_real_escape_string($uniqkey[25]),mysql_real_escape_string($uniqkey[26]),mysql_real_escape_string($uniqkey[27]),mysql_real_escape_string($uniqkey[28]),mysql_real_escape_string($uniqkey[29])) ";
mysql_query($query) or die(mysql_error());
I changed it to mysql_real_escape_string. Is this syntax correct? I am getting errors.
The process of encoding data which contains characters MySQL might interpret is called "escaping". You must escape your strings with mysql_real_escape_string, which is a PHP function, not a MySQL function, meaning you have to run it in PHP before you pass your query to the database. You must escape any data that comes into your program from an external source. Any data that isn't escaped is a potential SQL injection.
You have to escape your data before you build your query. Also, you can build your query programmatically using PHP's looping constructs and range:
// Build tag fields
$tags = 'tag' . implode(', tag', range(1,30));
// Escape each value in the uniqkey array
$values = array_map('mysql_real_escape_string', $uniqkey);
// Implode values with quotes and commas
$values = "'" . implode("', '", $values) . "'";
$query = "INSERT INTO alltags (id, $tags) VALUES ('', $values)";
mysql_query($query) or die(mysql_error());
Using mysql_real_escape_string is a safer approach to handling characters for SQL insertion/updating:
INSERT INTO YOUR_TABLE
VALUES
(mysql_real_escape_string($var1),
mysql_real_escape_string($var2))
Also, I'd change your columns back from TEXT to VARCHAR - searching, besides indexing, works much better.
Update for your update
Being that id is an auto_increment column you can:
leave it out of the list of columns, so you don't have to provide a value in the VALUES clause:
INSERT INTO alltags
(tag1,tag2,tag3,tag4,tag5,tag6,tag7,tag8,tag9,tag10,tag11,tag12,tag13,tag14,tag15,tag16,tag17,tag18,tag19,tag20,tag21,tag22,tag23,tag24,tag25,tag26,tag27,tag28,tag29,tag30)
VALUES
(mysql_real_escape_string($uniqkey[0]),mysql_real_escape_string($uniqkey[1]),mysql_real_escape_string($uniqkey[2]),mysql_real_escape_string($uniqkey[3]),mysql_real_escape_string($uniqkey[4]),mysql_real_escape_string($uniqkey[5]),mysql_real_escape_string($uniqkey[6]),mysql_real_escape_string($uniqkey[7]),mysql_real_escape_string($uniqkey[8]),mysql_real_escape_string($uniqkey[9]),mysql_real_escape_string($uniqkey[10]),mysql_real_escape_string($uniqkey[11]),mysql_real_escape_string($uniqkey[12]),mysql_real_escape_string($uniqkey[13]),mysql_real_escape_string($uniqkey[14]),mysql_real_escape_string($uniqkey[15]),mysql_real_escape_string($uniqkey[16]),mysql_real_escape_string($uniqkey[17]),mysql_real_escape_string($uniqkey[18]),mysql_real_escape_string($uniqkey[19]),mysql_real_escape_string($uniqkey[20]),mysql_real_escape_string($uniqkey[21]),mysql_real_escape_string($uniqkey[22]),mysql_real_escape_string($uniqkey[23]),mysql_real_escape_string($uniqkey[24]),mysql_real_escape_string($uniqkey[25]),mysql_real_escape_string($uniqkey[26]),mysql_real_escape_string($uniqkey[27]),mysql_real_escape_string($uniqkey[28]),mysql_real_escape_string($uniqkey[29])) ";
include id in the list of columns, which requires you use either value in its place in the VALUES clause:
NULL
DEFAULT
Here's an example using NULL as the id placeholder:
INSERT INTO alltags
(id,tag1,tag2,tag3,tag4,tag5,tag6,tag7,tag8,tag9,tag10,tag11,tag12,tag13,tag14,tag15,tag16,tag17,tag18,tag19,tag20,tag21,tag22,tag23,tag24,tag25,tag26,tag27,tag28,tag29,tag30)
VALUES
(NULL,mysql_real_escape_string($uniqkey[0]),mysql_real_escape_string($uniqkey[1]),mysql_real_escape_string($uniqkey[2]),mysql_real_escape_string($uniqkey[3]),mysql_real_escape_string($uniqkey[4]),mysql_real_escape_string($uniqkey[5]),mysql_real_escape_string($uniqkey[6]),mysql_real_escape_string($uniqkey[7]),mysql_real_escape_string($uniqkey[8]),mysql_real_escape_string($uniqkey[9]),mysql_real_escape_string($uniqkey[10]),mysql_real_escape_string($uniqkey[11]),mysql_real_escape_string($uniqkey[12]),mysql_real_escape_string($uniqkey[13]),mysql_real_escape_string($uniqkey[14]),mysql_real_escape_string($uniqkey[15]),mysql_real_escape_string($uniqkey[16]),mysql_real_escape_string($uniqkey[17]),mysql_real_escape_string($uniqkey[18]),mysql_real_escape_string($uniqkey[19]),mysql_real_escape_string($uniqkey[20]),mysql_real_escape_string($uniqkey[21]),mysql_real_escape_string($uniqkey[22]),mysql_real_escape_string($uniqkey[23]),mysql_real_escape_string($uniqkey[24]),mysql_real_escape_string($uniqkey[25]),mysql_real_escape_string($uniqkey[26]),mysql_real_escape_string($uniqkey[27]),mysql_real_escape_string($uniqkey[28]),mysql_real_escape_string($uniqkey[29])) ";
I want to really stress that you should not setup your columns like that.
Slight improvement of meagar's answer:
EDIT: meagar updated his post, so his answer is now better.
$query = 'INSERT INTO alltags (id, ';
// append tag1, tag2, etc.
$query .= 'tag' . implode(', tag', range(1, 30)) . ") VALUES ('', ";
// escape each value in the uniqkey array
$escaped_tags = array_map('mysql_real_escape_string', $uniqkey);
// implode values with quotes and commas, and add closing bracket
$query .= "'" . implode("', '", $escaped_tags) . "')";
// actually query
mysql_query($query) or die(mysql_error());
Please look at meagars answer. This is the correct code.
If you want to use the misguided mysql_query() function, then you have to break up the SQL string as follows:
mysql_query(
"INSERT INTO whateever (col1,col2,col3,col4) VALUES ("
. mysql_real_escape_string($col1)
. ","
. mysql_real_escape_string($col2)
. ","
. mysql_real_escape_string($col3)
. ","
. mysql_real_escape_string($col4)
. ")"
);
Or since you have an array, use the clever method call to escape all at once:
$uniqkey = array_map("mysql_real_escape_string", $uniqkey);
mysql_query("USE THE ESCAPED ARRAY THEN DIRECTLY ('$uniqkey[0]', '$uniqkey[1]', '$uniqkey[2]', '$uniqkey[3]', ...");