Hi I have this query where I am inserting information into a database.
Submitting the form works as intended. However, when using ' (apostrophes) within the text entered,
I receive a PDOException SQLSTATE[42000] Syntax error or access violation: 1064
$result = $conn->prepare("UPDATE `news_articles`
SET `postedby`=:postedby,`title`=:title,
`short_title`=:short_title,
`article_image`=:article_image,
`contents`=:contents,
`datetime`=:datetime,
`event_datetime`=:event_datetime,
`type`=:type
WHERE `articleid`=:articleid");
$result->bindParam(':articleid', $articleid);
$result->bindParam(':postedby', $postedby);
$result->bindParam(':title', $title);
$result->bindParam(':short_title', $short_title);
$result->bindParam(':article_image', $article_image);
$result->bindParam(':contents', $contents);
$result->bindParam(':datetime', $datetime);
$result->bindParam(':event_datetime', $event_datetime);
$result->bindParam(':type', $type);
$result->execute();
Does anybody know why this is?
I am not 100% sure of this but if you use the third parameter of the ->bindParam() to inform it of the data type it may well be all you need to correct this issue
So that would be specifically
$result->bindParam(':contents', $contents, PDO::PARAM_STR);
But you should use it on all your ->bindParam() calls
Manual http://php.net/manual/en/pdostatement.bindparam.php
and Param constants http://php.net/manual/en/pdo.constants.php
Related
I am currently undergoing the process to convert my code from MySQL to PDO however I am having an issue passing a variable. I have edited the content of the variable to give you an idea of exactly what is happening.
$status = 'Pending';
$stmt = $db->prepare("INSERT INTO
cusbuilder_sites(userid,name,imgurl,url,explain,status,incustom) VALUES
(:userid,:campname,:imgurl,:targeturl,:explain,:status,:incustom)");
$explain = '<p>Testing Input</p>';
$stmt->bindParam(':userid', $username);
$stmt->bindParam(':campname', $_POST['campname']);
$stmt->bindParam(':imgurl', $_POST['imgurl']);
$stmt->bindParam(':targeturl', $_POST['targeturl']);
$stmt->bindValue(':explain', $explain, PDO::PARAM_STR);
$stmt->bindParam(':status', $status);
$stmt->bindParam(':incustom', $_POST['incustom']);
$stmt->execute();
Now this is the error I am getting:
: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 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 'explain,status,incustom) VALUES ('myuserid','testing12','http://testingsite.com' at line 1'
As you can see the $explain variable contains HTML code and when I remove the p tags it works fine but I need it to actually store the HTML in the database as it did with MySQL.
I have read the answers to this question and have checked if magic_quotes or gpc are enabled. They aren't. In my previous code I was using mysql_real_escape_string which obviously I cannot use in PDO so I just want to know how do i pass HTML in a variable and insert it into a database using PDO?
For those who are going to answer 'use bindValue instead of bindParam' you will see I have already done this and the error is the same.
This doesn't have anything to do with HTML. The SQL query itself is invalid. explain is a reserved word. Enclose your identifiers in back-ticks (assuming MySQL, other characters may be used by other databases) to specify them as identifiers:
INSERT INTO `cusbuilder_sites`
(`userid`,`name`,`imgurl`,`url`,`explain`,`status`,`incustom`) VALUES
(:userid,:campname,:imgurl,:targeturl,:explain,:status,:incustom)
I am trying to get a database query page to work but cant seem to do so.
my Code so far (here I tried bindValue, but previously tried bindParam and got the same result):
var_dump($_POST);
$dbh = new PDO ("mysql:host=$myServer;dbname=$myDB", $myUser, $myPw);
$columName = $_POST["columName"];
$tblName = $_POST["tblName"];
$valueName = $_POST["valueName"];
$specificValue = $_POST["specificValue"];
$stmt = $dbh->prepare("SELECT :columName FROM :tblName Where :valueName = :specificValue");
$stmt->bindValue(":columName", $columName);
$stmt->bindValue(":valueName", $valueName);
$stmt->bindValue(":tblName", $tblName);
$stmt->bindValue(":specificValue", $specificValue);
$stmt->execute();
$result = $stmt->fetch();
if(empty($result)){echo "empty";}
print_r ($stmt);
print_r($result);
Printing result and $stmt brings following results:
empty
PDOStatement Object ( [queryString] => SELECT :columName FROM :tblName Where :valueName = :specificValue )
What did I do wrong? What could I try to get it to work?
I am new to the whole coding thing, so please ask if I forgot any code or other important information!
Thanks!
Placeholder parameters can only represent VALUES in the query. Tables, field names, sql key words, etc.. are all impossible to use placeholders on.
If you need to build a dynamic query and replace field/table names, then you'll have to use good old string construction methods, and be aware that you'll be opening yourself to SQL injection attacks again:
$sql = "SELECT * FROM $foo WHERE $bar = :baz";
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':baz', $baz);
I'm afraid you need to rethink how parameterised queries work. It's not just a case of magically inserting data in a safe way. It's about distingushing between the structure of a query and the data.
So the database name, the column names, the table names and any SQL keywords are part of the structure of the query. Every time you run the query, they will be the same.
The data, however, can change between running the query.
So the structure needs to be in place when the query is prepared. However, you obviously can't just plonk the $columName variable etc into the query for SQL injection reasons. If you really need to have flexible queries like this (nb that you probably don't) you need to create a whitelist of allowed values, either in your code or retrieved from the database.
Your query is invalid (you're using parameters for object identifiers) but you are not getting any notification because you have neither configured PDO to throw exceptions nor are calling the error check functions manually.
Add the PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION option to PDO's constructor:
$dbh = new PDO ("mysql:host=$myServer;dbname=$myDB", $myUser, $myPw, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
Once you do so, you'll get a prompt exception on the exact issue, e.g.:
PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064
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 ''user' Where 'login' = 'john'' at line 1 in [...]
As you can see, this is trying to run a query like (e.g.):
SELECT 'user_id'
FROM 'user'
Where 'login' = 'john'
Additionally, beware of SQL injection. It's terribly unsafe to compose SQL queries using data from $_POST.
So the following code has been bugging me a bit:
$stm = $pdo->prepare("SELECT * FROM urls WHERE account=? AND NOT deleted LIMIT ?, 4");
$stm->execute($user, ($request-1)*4);
Whenever I execute this query it returns this error:
Syntax error or access violation: 1064 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 ''0', 4' at line 1'
Upon looking it up it seems that using the ? placeholders automatically puts quotes around it unless you specify with a bindParam. Is there any way to fix this without having to use the bingparam function?
This is a known issue and why the limit should not really be used with bound parameters. However, you can overcome this by binding the parameter individually and naming it an int.
$stm = $pdo->prepare("SELECT * FROM urls WHERE account=? AND NOT deleted LIMIT ?, 4");
$stm->bindValue(1, $user);
$stm->bindValue(2, ($request-1)*4), PDO::PARAM_INT);
$stm->execute();
If you read PDOStatement::execute() it is caused because binding on the execute causes all parameters to be bound as strings.
As Your Common Sense pointed out, you can disable emulation mode and let MySQL sort out the placeholders by itself, though this may not work with all DB drivers (though will with MySQL) by:
$pdo->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
Or you can do an intval or type-cast to an int and put it directly within your statement if you'd prefer to do it that way.
I want to use a prepared statement in which the passed-in parameters are for the ORDER BY and LIMIT clauses, like so:
$sql = 'SELECT * FROM table ORDER BY :sort :dir LIMIT :start, :results';
$stmt = $dbh->prepare($sql);
$stmt->execute(array(
'sort' => $_GET['sort'],
'dir' => $_GET['dir'],
'start' => $_GET['start'],
'results' => $_GET['results'],
)
);
But $stmt->fetchAll(PDO::FETCH_ASSOC); returns nothing.
Can someone point out what's the wrong thing I am doing? Can it be done? If not,what should I reference for a complete list of clauses where parameters can be used?
After using :
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
I got the message :
Uncaught exception 'PDOException' with
message 'SQLSTATE[42000]: Syntax error
or access violation: 1064 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 ''0', '10'' at line 1
So, when you use an array for execute, it consider your inputs as string which is not a good idea for LIMIT
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT * FROM table ORDER BY :sort :dir LIMIT :start, :results";
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':start', $_GET['start'], PDO::PARAM_INT);
$stmt->bindParam(':results', $_GET['results'], PDO::PARAM_INT);
$stmt->bindParam(':sort', $_GET['sort']);
$stmt->bindParam(':dir', $_GET['dir']);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($data);
Prepared statements allow the DBMS to generate a query plan for your query before actually executing the query for your supplied parameters. Changing the fields for ORDER BY requires a different query plan, because ordering you data in different ways can drastically affect how the DBMS might choose to get the data: for instance, certain indexes may help in one case but not in another. For this reason the ORDER BY fields should form part of the SQL string passed into the prepare() method, rather than being bound to the query prior to execute().
As for the LIMIT clause, it's not clear whether its parameters would affect the query plan, so these may be bound later, possibly depending upon your DBMS. According to this SO answer it should be allowed.
You can't bind a parameter to specify a language keyword or a field name - it has to be replacing a literal. Therefore, your limit values I think are fine, but your order by is not. It will be best for you to manually replace sort and dir in the string. Escape them but don't use the DB tools to do so, since they aren't string literals. Basically ensure no special characters are present.
Although this question is rather old, I think it might still be of interest. For me it worked after I
used bindParam in combination with PDO::PARAM_INT like suggested before
converted the variable content into an integer value by invoking intval()
The relevant part of the code then looks like this:
$stmt->bindParam(':start', intval($_GET['start']), PDO::PARAM_INT);
$stmt->bindParam(':number', intval($_GET['number']), PDO::PARAM_INT);
Without using intval() I also received the error Syntax error or access violation: 1064 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 ''0', 10' at line 1
I'm having a problem with a query prepared in PHP with PDO. The code:
$link = new PDO("mysql:dbname=$dbname;host=127.0.0.1",$username,$password);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$query = $link->prepare("SELECT locality_name FROM :passedday GROUP BY locality_name ORDER BY locality_name DESC");
$query->bindParam(":passedday",$day); //Where day is, well, a day passed to the script elsewhere
$query->execute();
$result = $query->fetchAll();
$link = null;
//Do things with the $result.
The error message I am getting is:
SQLSTATE[42000]: Syntax error or access violation: 1064 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 ''05_26_09' GROUP BY locality_name ORDER BY locality_name DESC' at line 1
When I execute the query on the server directly, it returns the appropriate result set without any problem. Any ideas what I'm doing wrong?
TIA.
Edit:
$day is passed as a GET argument. So, http://127.0.0.1/day.php?day=05_26_09 leads to $day = $_GET['day'];.
If 05_26_09 is supposed to bet the table's name, then I guess you've an escaping problem. Is your local operating system different from the live server?
I don't think you can use bindValue()/bindParam() for something else than values (eg. table name, field name). So I'm a bit suprised, that it works on your local system.
PDO uses mysql's C-API for prepared statements.
http://dev.mysql.com/doc/refman/5.0/en/mysql-stmt-prepare.html says:The markers are legal only in certain places in SQL statements. [...] However, they are not allowed for identifiers (such as table or column names)As a rule of thumb I use: "if you can't wrap it in single-quotes in an ad-hoc query string you can't parametrize it in a prepared statement"