I need cut a piece of text fragment starting with "<div".
I have some like this:
$query = mysql_query("Select * from products_description");
while($row = mysql_fetch_array($query))
{
$usun = substr($row['products_description'], 0, strpos($row['products_description'], "<div"));
mysql_query('UPDATE products_description SET products_description = '.$usun.' WHERE products_id = '.$row['products_id'].'');
}
Unfortunately it does not work
If we echo out the SQL text (the UPDATE statement the code is attempting to execute), we'd see part of the problem.
String literals need to be enclosed in single quotes.
... SET products_description = 'string literal' WHERE ...
^ ^
Another issue is that we don't see any guarantee that the string literal value isn't going to include potentially unsafe values, such as a single quote. Potentially unsafe values should be properly escaped before they are included in SQL text.
Of course, if we used a prepared statement with bind placeholders, we would entirely avoid both of those problems.
Assuming that the PHP substr function is returning the value you want assigned to the column... there's really no need to process RBAR (row by agonizing row), when we could accomplish the same thing in one swoop.
UPDATE mytable SET mycol = SUBSTRING_INDEX(mycol,'<div',1) ;
We can test our expressions in a SELECT statement, before we commit to running an UPDATE statement. For example:
SELECT t.mycol
, SUBSTRING_INDEX(t.mycol,'<div',1) AS newval
FROM mytable t
Firstly, use PDO rather than mysqli_ or mysql_ functions. Then you can use parameter binding. It helps to prevent SQL injection.
You should quote your $usun before concatenating it into the SQL request:
$usun=mysql_real_escape_string($usun);
It's unclear why the exact code in your question isn't working, (although the quoting issue others have pointed out is definitely part of the problem) but this may answer the question anyway since I'm proposing something completely different.
Try just doing one update query to remove the <div at the beginning of the string instead of the select/loop/update approach.
UPDATE products_description
SET products_description = SUBSTRING(products_description FROM 5)
WHERE products_description LIKE '<div%'
Or if you want to remove everything after the <div:
UPDATE products_description
SET products_description = '<div'
WHERE products_description LIKE '<div%'
Related
I am currently working on a php project and used the word 'value' as a column name. The problem being that when I run the query, it overwrites all entries in the database, even though I have a delimiter (primary key = *). I have tried everything I can think of to get this to work, and it hasn't yet. here is the complete line of code:
$SqlStatement = "UPDATE rev_exp SET Date_Entered = '".date('Y-m-d')."', Description = '".$_POST['txtUtilityType']." ".$_POST['txtAccountNumber']." ".$_POST['txtDateAdded']."', `Value` = ".$_POST['txtValueBalance'].", Notes = '".$_POST['txtNotes']."' WHERE PK_Rev_Exp = ".$row['FK_Rev_Exp'];
Note here, that $row['FK_Rev_Exp'] is the delimiter I was talking about. It is being pulled accurately from a previous query. Also, please ignore any sql injection problems, I'm just working on getting the project functional, I can optimize later.
EDIT 1: I have also tried enclosing the "value" in everything I can think of that may get rid of this problem, but no luck.
EDIT 2: I also don't think it is a problem with the statement itself, as I directly entered the statement into the mysql command line and it only affected 1 row, possibly a php problem?
EDIT 3: Full block, including the execution of the sql. Here, ExecuteSQL runs all necessary mysqli statements to execute the sql command. it takes in a sql statement and a true/false if there is a result set:
$SqlStatement = "UPDATE rev_exp SET Date_Entered = '".date('Y-m-d')."', Description = '".$_POST['txtUtilityType']." ".$_POST['txtAccountNumber']." ".$_POST['txtDateAdded']."', `Value` = '".$_POST['txtValueBalance']."', Notes = '".$_POST['txtNotes']."' WHERE PK_Rev_Exp = ".$row['FK_Rev_Exp'];
ExecuteSQL($SqlStatement, false);
I can't figure it out, and any help would be appreciated.
I think your problem is not about mysql reserver keywords because your correctly surrounded Value with backtick and that makes database understand this is a field. I'm more concerned about treating not integers as integers so i would suggest to surround with quotes '' your value since it is a decimal
`Value` = '".$_POST['txtValueBalance']."',
The table has company names which are not escaped.
My qry looks like
$sql = "SELECT id FROM contact_supplier WHERE name = '$addy' LIMIT 1";
The problem comes in where the company name values in the table are sometimes things like "Acme Int'l S/L".
(FYI: values of the $addy match the DB)
Clearly, the values were not escaped when stored.
How do I find my matches?
[EDIT]
Ahah!
I think I'm we're on to something.
The source of the $addy value is a file
$addresses = file('files/addresses.csv');
I then do a
foreach ($addresses as $addy) {}
Well, when I escape the $addy string, it's escaping the new line chars and including "\r\n" to the end of the comparison string.
Unless someone suggests a more graceful way, I guess I'll prob strip those with a str_replace().
:)
[\EDIT]
Why do you think the data already stored in the table should be escaped?
You should escape data only right before it is written directly into a text-based language, e.g. as a part of an SQL query, or into an HTML page, or in a JavaScript code block.
When the query is executed, there's nothing espaced. MySQL transforms it and inserts, otherwise it wouldn't insert and gives error because of syntax or we escape them for security like sql injection.
So your query with escaped values will be working fine with the data in your database.
If the values were not escaped when stored then they would have caused SQL errors when you tried to enter them.
The problem is that the data is not being escaped when you make the query.
Quick hack: Use mysql_real_escape_string
Proper solution: Don't build SQL by mashing together strings. Use prepared statements and parameterized queries
Another option would be to change your query to this...
$sql = "SELECT id FROM contact_supplier WHERE name = \"$addy\" LIMIT 1";
Use mysql_real_escape_string:
$addy = mysql_real_escape_string($addy);
Or try using parameterized queries (PDO).
Regarding this statement:
Clearly, the values were not escaped when stored.
This is incorrect logic. If the values weren't escaped in the original INSERT statement, the statement would have failed. Without escaping you'd get an error along the lines of syntax error near "l S/L' LIMIT 1". The fact that the data is correctly stored in the database proves that whoever inserted it managed to do it correctly (either by escaping or by using parameterized queries).
If you are doing things correctly then the data should not stored in the database in the escaped form.
The issue turned out to be new-line characters
The source of the $addy value starts out like this
$addresses = file('files/addresses.csv');
I then goes through
foreach ($addresses as $addy) {}
When I escape the $addy string, it's escaping the new line chars and inserting "\r\n" on the end of the comparison string.
As soon as I dropped those chars with string_replace() after escaping, everything went swimmingly
Thanks-a-BUNCH for the help
Where and when do you use the quote method in PDO? I'm asking this in the light of the fact that in PDO, all quoting is done by the PDO object therefore no user input should be escaped/quoted etc. This makes one wonder why worry about a quote method if it's not gonna get used in a prepared statement anyway?
When using Prepared Statements with PDO::prepare() and PDOStatement::execute(), you don't have any quoting to do : this will be done automatically.
But, sometimes, you will not (or cannot) use prepared statements, and will have to write full SQL queries and execute them with PDO::exec() ; in those cases, you will have to make sure strings are quoted properly -- this is when the PDO::quote() method is useful.
While this may not be the only use-case it's the only one I've needed quote for. You can only pass values using PDO_Stmt::execute, so for example this query wouldn't work:
SELECT * FROM tbl WHERE :field = :value
quote comes in so that you can do this:
// Example: filter by a specific column
$columns = array("name", "location");
$column = isset($columns[$_GET["col"]]) ? $columns[$_GET["col"]] : $defaultCol;
$stmt = $pdo->prepare("SELECT * FROM tbl WHERE " . $pdo->quote($column) . " = :value");
$stmt->execute(array(":value" => $value));
$stmt = $pdo->prepare("SELECT * FROM tbl ORDER BY " . $pdo->quote($column) . " ASC");
and still expect $column to be filtered safely in the query.
The PDO system does not have (as far as I can find) any mechanism to bind an array variable in PHP into a set in SQL. That's a limitation of SQL prepared statements as well... thus you are left with the task of stitching together your own function for this purpose. For example, you have this:
$a = array(123, 'xyz', 789);
You want to end up with this:
$sql = "SELECT * FROM mytable WHERE item IN (123, 'xyz', 789)";
Using PDO::prepare() does not work because there's no method to bind the array variable $a into the set. You end up needing a loop where you individually quote each item in the array, then glue them together. In which case PDO::quote() is probably better than nothing, at least you get the character set details right.
Would be excellent if PDO supported a cleaner way to handle this. Don't forget, the empty set in SQL is a disgusting special case... which means any function you build for this purpose becomes more complex than you want it to be. Something like PDO::PARAM_SET as an option on the binding, with the individual driver deciding how to handle the empty set. Of course, that's no longer compatible with SQL prepared statements.
Happy if someone knows a way to avoid this difficulty.
A bit late anwser, but one situation where its useful is if you get a load of data out of your table which you're going to put back in later.
for example, i have a function which gets a load of text out of a table and writes it to a file. that text might later be inserted into another table. the quote() method makes all the quotes safe.
it's real easy:
$safeTextToFile = $DBH->quote($textFromDataBase);
I'm trying to use odbc_prepare and odbc_execute in PHP as follows:
$pstmt=odbc_prepare($odb_con,"select * from configured where param_name='?'");
$res=odbc_execute($pstmt,array('version'));
var_dump($res); //bool(true)
$row = odbc_fetch_array($pstmt);
var_dump($row); //bool(false)
The first var_dump returns true so the execute succeeds, but there is no row returned. A row does indeed exist with the param_name = 'version'. Why is no row returned?
To make things interesting, I ran another very simple example in php using a prepared insert.
$pstmt=odbc_prepare($odb_con,"insert into tmp1 values(?,'?')");
This line, by itself, inserted a row into the database!! Surely this is just wrong? The data entered was col 1 = blank, col 2 = ?
Any advice on where to start fixing this would be appreciated, thanks.
Edit: This is in PHP 5.2.8
Try removing the single quotes from the query string and adding them to the parameter value itself:
$pstmt=odbc_prepare($odb_con,"select * from configured where param_name=?");
$res=odbc_execute($pstmt,array(" 'version'"));
var_dump($res); //bool(true)
$row = odbc_fetch_array($pstmt);
var_dump($row); //bool(false)
The single space character at the beginning of the parameter value is very important--if the space is not there, it will treat the variable as a path to a file.
From http://www.php.net/manual/en/function.odbc-execute.php:
If you wish to store a string which
actually begins and ends with single
quotes, you must add a space or other
non-single-quote character to the
beginning or end of the parameter,
which will prevent the parameter from
being taken as a file name.
when I read this paragraph
Any parameters in parameter_array which start and end with single quotes will be taken as the name of a file to read and send to the database server as the data for the appropriate placeholder.
If you wish to store a string which actually begins and ends with single quotes, you must add a space or other non-single-quote character to the beginning or end of the parameter, which will prevent the parameter from being taken as a file name. If this is not an option, then you must use another mechanism to store the string, such as executing the query directly with odbc_exec()).
It seems to me that it isn't necessary to add single quotes ' to a string, only if you really want to have the quotes as text in the DB
Therefore if I only want to insert the text, without the single quotes I would write something like that ...
see this example from odbc-prepare
http://www.php.net/manual/en/function.odbc-prepare.php
Use this example for IBM DB/2:
$q = "update TABLE set PASS=? where NAME=?";
$res = odbc_prepare ($con, $q);
$a = "secret"; $b="user";
$exc = odbc_execute($res, array($a, $b));
This would result in the following statement
$pstmt=odbc_prepare($odb_con,"select * from configured where param_name=?");
$name = "version";
$params = array($name);
$res=odbc_execute($pstmt,$params);
var_dump($res); //bool(true)
$row = odbc_fetch_array($pstmt);
var_dump($row); //bool(false)
See that I not only removed the qoutes for the value in the params array but also removed the qoutes in the SQL statement.
please give feedback if this was right
You should not enclose variables in quotes in a prepared statement:
$pstmt=odbc_prepare($odb_con,"select * from configured where param_name=?");
$res=odbc_execute($pstmt,array(" 'version'"));
should be:
$pstmt=odbc_prepare($odb_con,"select * from configured where param_name=?");
$res=odbc_execute($pstmt,array("version"));
Question marks represent parameter placeholders, the value passed is meant to represent an unescaped, unenclosed value, which will be properly escaped by the SQL interpreter.
EDIT:
Gah, ignore me, misread php.net
odbc_fetch_array accepts as it's parameter the result of odbc_execute, you seem to be passing in the prepared statement.
What DBMS are you using? The fact that the lone insert prepare statement seems to be executed against the database rather than being prepared points to either a poor implementation of php (unlikely) or the DBMS not supporting prepared sql. If the latter is the case it is possible that their way of supporting the command with out the functionality is just to execute the statement leading to the results you get. If the DBMS does support prepared statements and the php implementation handles it properly there is some kind of issue with the insert being executed which also needs some investigation.
Did you try using double quotes? i.e.
$res=odbc_execute($pstmt,array("version"));
This might be a stupid question.
Or maybe my hacking skills are limited (I don't practice them at all).
I have a query that looks like this:
<?php
$query =<<<eot
SELECT table_x.field1,
table_x.field2,
table_y.*,
table_z.field4
FROM (
SELECT ...
) as table_y
LEFT JOIN table_x
ON table_x.field1 = table_y.field_x
LEFT JOIN table_z
ON table_z.field1 = table_y.field_z
WHERE table_x.field3 = '$something'
AND table_z.field4 = '1'
AND table_z.field5 = '2'
eot;
?>
I have a lot of other tests on $something before it gets used, like $something = explode(' ',$something); (which later result in a string) none of them intend to prevent injection but they make it hard for the given injection to get as is to the actual query.
However, there are ways. We all know how easy it is to replace a space for something else which is still valid..
So, it's not really a problem to make a potentially harmful piece of SQL reach that $something...
But is there any way to comment the rest of the original query string if it is multi-line?
I can comment AND table_z.field4 = '1' using ;-- but can't comment the following AND table_z.field5 = '2'
Is it possible to open a multi-line comment /* without closing it or something looked like and therefore allow the injection to ignore the multi-line query?
It's not safe. Even if it can't comment out the rest, it could prefix it with SELECT * FROM my_table WHERE 1=1.
$something = "'; DROP TABLE table_x; SELECT * FROM table_z WHERE '1' = '1";
Use prepared statements to be safe:
http://www.php.net/manual/en/pdo.prepare.php
String interpolation always has the risk of code injection if your input is not sufficiently cleaned.
Removing the possibility to execute arbitrary code is the easier AND much safer way.
#Techpriester: that's not what a prepared statement is.
http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html (old version, same thing)
PDO is a database abstraction layer that "prepares statements", but a prepared statement is something entirely different!