Error appears while searching joke from relational database - php

I am using Server version 10.1.21-MariaDB and mysql for performing data operation. I am creating mini search tool for searching jokes.The overview of how i am performing it is shown in image. Everything works fine but when i try to execute sql statement,it shows syntax error. I tried to dig inside it but as i am quite new to this stuff,i lost here and there digging the exact way of using syntax. The error is shown in bold letter and code is provided below where error occurs.I think error must be inside the try block,please help me to sort this out.
//query logic
$select = 'SELECT id,joketext ';
$from = 'FROM joke_info';
$where = 'WHERE TRUE';
$placeholders = array();
if(isset($_GET['author']) != ''){
$where .= " AND authorid = :authorid";
$placeholders[':authorid'] = $_GET['author'];
}
if(isset($_GET['category']) != ''){
$from .= ' INNER JOIN jokecategory ON id = jokeid';
$where .= " AND categoryid = :categoryid";
$placeholders[':categoryid'] = $_GET['category'];
}
if ($_GET['text'] != '')
{
$where .= " AND joketext LIKE :joketext";
$placeholders[':joketext'] = '%' . $_GET['text'] . '%';
}
print_r($placeholders);
try
{
$sql = $select . $from . $where;
$s = $pdo->prepare($sql);
$s->execute($placeholders);
}catch (PDOException $e)
{
$error = 'Error fetching jokes. ';
echo $error.$e->getMessage();
exit();
}
Error Says this:
Array ( [:authorid] => 6 [:categoryid] => 10 [:joketext] => %been working% ) Error fetching jokes. SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'TRUE AND authorid = '6' AND categoryid = '10' AND joketext LIKE '%been working%'' at line 1

Your generated query after $sql = $select . $from . $where; will be something like SELECT id,joketext FROM joke_info WHERE TRUE
So there is no space between joke_info and Where clause
It should be $from = ' FROM joke_info' and $where = ' WHERE TRUE '; instead of $from = 'FROM joke_info' and '$where ='WHERE TRUE';

Ther is no space between $from and $where variables. Currently they are concatenating to: 'FROM joke_infoWHERE TRUE'. Try giving a space in the $from variable.

Related

Error in PDO Update Function

$table="menu_permission";
$field = array('permission'=>$mnuprmis);
$ob->update($table,$field,'staff_id',$stfid);
public function update($table, $fields, $wherefield, $wherefieldvalues)
{
$sql = "update $table set";
foreach ( $fields as $fieldname => $sfieldvalue )
$sql .= $fieldname."= '".$sfieldvalue."',";
$sql = substr($fldquery,0,strlen($fldquery)-1);
$sql .=" where $wherefield = '$wherefieldvalues'";
$q = $this->conn->prepare($sql);
$q->execute();
return true;
}
The error
Fatal error: 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 'where staff_id = '1'' at line 1'
in G:\xampp\htdocs\live\Billing Suryas\model\DBConfig.php:171
Stack trace: #0 G:\xampp\htdocs\live\Billing Suryas\model\DBConfig.php(171): PDOStatement->execute()
#1 G:\xampp\htdocs\live\Billing Suryas\pages\permission_pages.php(257): Connection->update('menu_permission', Array, 'staff_id', '1')
#2 {main} thrown in G:\xampp\htdocs\live\Billing Suryas\model\DBConfig.php on line 171
There is no such freaking thing as an $fldquery
$sql = substr($fldquery,0,strlen($fldquery)-1);
^^^ ^^^
Hence your query is only
$sql .=" where $wherefield = '$wherefieldvalues'";
Which results in
where staff_id = '1' // This is your COMPLETE query
That is just one of the problems and it will be fixed when you fix the typo and put in correct variable name there. However a bigger problem will be evident if you read this
How can I prevent SQL injection in PHP?
It might have had to do with the fact that you put single quotes around numeric values, which isn't necessary and might break your query since your DB might regard it as a string instead of a number.
$table="menu_permission";
$field = array('permission'=>$mnuprmis);
$ob->update($table,$field,'staff_id',$stfid);
public function update($table, $fields, $wherefield, $wherefieldvalues)
{
//
// COMPILE QUERY
$sql = "update $table set ";
$col_values_array = array();
foreach ( $fields as $fieldname => $sfieldvalue ) {
$value = is_numeric($sfieldvalue) ? $sfieldvalue : "'$sfieldvalue'";
$col_values_array[] = "$fieldname = $value";
}
$sql .= implode("," , $col_values_array);
$sql .= " where $wherefield = '$wherefieldvalues'";
//
// EXECUTE QUERY
//$q = $this->conn->prepare($sql); --> not required when not using parametrised queries
//$q->execute(); --> not required when not using parametrised queries
$this->conn->query($sql);
return true;
}
Also consider using prepared statements to be safe against SQL injection.

No active transaction

I'm trying to use transactions with PDO, with the following code
try
{
$bdd = new PDO('mysql:host=HOSTNAME;dbname=DATABASENAME', 'USERNAME', 'PASSWORD');
}
catch(Exception $e)
{
die('Error : '.$e->getMessage());
}
$qry = 'UPDATE table SET field = CASE';
foreach($elements as $el){
$qry .= ' WHEN id = '. $el['id'] .' THEN '. $el['value'];
}
$qry .= ' ELSE field END, SET update_date = CASE';
foreach($elements as $el){
$qry .= ' WHEN id = '. $el['id'] .' THEN NOW()';
}
$qry .= ' ELSE update_date END';
$update = $bdd->prepare($qry);
$bdd->beginTransaction();
try {
$update->execute();
$bdd->commit();
}
catch(Exception $e) {
$bdd->rollback();
echo 'Error : '.$e->getMessage().'<br />';
echo 'N° : '.$e->getCode();
exit();
}
But I get the following error (and the table is not updated) :
Fatal error: Uncaught exception 'PDOException' with message 'There is no active transaction' in script.php:106
Stack trace:
#0 script.php(106): PDO->rollBack() #1 {main} thrown in script.php on line 106
(Line 106 is $bdd->rollback();)
I understand that it's telling me there is no transaction going on, but... there should be, with $bdd->rollback();...
Thanks for any help you can give !
EDIT : The database engine is MyISAM.
I have additional info after further testing :
I simplified the $qry in my question because I thought it was irrelevant, but it seems it isn't. The query I'm actually using is a much longer one, updating multiple elements with the following code (I also modified the code up there ^ in the original question) :
$qry = 'UPDATE table SET field = CASE';
foreach($elements as $el){
$qry .= ' WHEN id = '. $el['id'] .' THEN '. $el['value'];
}
$qry .= ' ELSE field END, SET update_date = CASE';
foreach($elements as $el){
$qry .= ' WHEN id = '. $el['id'] .' THEN NOW()';
}
$qry .= ' ELSE update_date END';
It seems that the length of the query and/or the number of updated lines is causing my issue :
when updating 72 lines at most (the query is 3463 characters long, all spaces included), the table is updated, and vardump($bdd->beginTransaction();) returns bool(true) (regardless of wether it's before or after the $update = $bdd->prepare($qry) line.
when updating 73 lines or more (the query is 3509 characters long, all spaces included, when it updates 73 lines), the table is not updated, and vardump($bdd->beginTransaction();) returns bool(false) (once again, regardless of wether it is before or after the $update = $bdd->prepare($qry) line.
Hints on why, and how I can fix it are appreciated.
Thanks again
EDIT 2 : I switched the engine to InnoDB. The issue still stands.
Move
$bdd->beginTransaction();
to above your query:
$qry = 'UPDATE table SET field = value'
$update = $bdd->prepare($qry);
EDIT:
You are using MyISAM engine which does not support transactions. Update your tables to use InnoDB.

How can I perform an SQL injection on the following PHP mysql_* code?

I have an existing application which used to use the deprecated mysql_* functions to perform database queries. I have since changed most database access (and all that has user input) to PDO, so I believe I am relatively safe from injection attacks. However, I was wondering how one would perform an injection attack on the previous code just so I can demonstrate how unsafe it is should the need arise.
I have a link in the format:
http://localhost/api/view.php?id=
Which is then passed, unsanitized, into the select function below:
$db->select('invitations','Replied, Response, Registered',null,"Id = '".$id."'");
$res = $db->getResult();
I then do a var_dump() to see the result.
I have tried something like:
http://localhost/api/view.php?id=<id>'
=> array(1) { [0]=> string(185) "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 ''<id>''' at line 1" }
http://localhost/api/view.php?id=<id>" or 1=1" => array(0) { }
But it doesn't seem like those types of queries would be successful. Ideally, I would want to be able to do something severe. I was hoping for something like '); DROP TABLE users;--, but I cannot seem to make anything of the sort occur.
Here is the full select function:
public function select($table, $rows = '*', $join = null, $where = null, $order = null, $limit = null){
// Create query from the variables passed to the function
$q = 'SELECT '.$rows.' FROM '.$table;
if($join != null){
$q .= ' JOIN '.$join;
}
if($where != null){
if (is_array($where)) {
$filter = $where;
$where = " 0 = 0 ";
$qs = "";
for ($i=0;$i<count($filter);$i++){
switch($filter[$i]['data']['type']){
case 'string' : $qs .= " AND ".$filter[$i]['field']." LIKE '%".$filter[$i]['data']['value']."%'"; Break;
case 'list' :
if (strstr($filter[$i]['data']['value'],',')){
$fi = explode(',',$filter[$i]['data']['value']);
for ($q=0;$q<count($fi);$q++){
$fi[$q] = "'".$fi[$q]."'";
}
$filter[$i]['data']['value'] = implode(',',$fi);
$qs .= " AND ".$filter[$i]['field']." IN (".$filter[$i]['data']['value'].")";
}else{
$qs .= " AND ".$filter[$i]['field']." = '".$filter[$i]['data']['value']."'";
}
Break;
case 'boolean' : $qs .= " AND ".$filter[$i]['field']." = ".($filter[$i]['data']['value']); Break;
case 'numeric' :
switch ($filter[$i]['data']['comparison']) {
case 'eq' : $qs .= " AND ".$filter[$i]['field']." = ".$filter[$i]['data']['value']; Break;
case 'lt' : $qs .= " AND ".$filter[$i]['field']." < ".$filter[$i]['data']['value']; Break;
case 'gt' : $qs .= " AND ".$filter[$i]['field']." > ".$filter[$i]['data']['value']; Break;
}
Break;
case 'date' :
switch ($filter[$i]['data']['comparison']) {
case 'eq' : $qs .= " AND ".$filter[$i]['field']." = '".date('Y-m-d',strtotime($filter[$i]['data']['value']))."'"; Break;
case 'lt' : $qs .= " AND ".$filter[$i]['field']." < '".date('Y-m-d',strtotime($filter[$i]['data']['value']))."'"; Break;
case 'gt' : $qs .= " AND ".$filter[$i]['field']." > '".date('Y-m-d',strtotime($filter[$i]['data']['value']))."'"; Break;
}
Break;
}
}
$where .= $qs;
}
$q .= ' WHERE '.$where;
}
if($order != null){
$q .= ' ORDER BY '.$order;
}
if($limit != null){
$q .= ' LIMIT '.$limit;
}
// Check to see if the table exists
if($this->tableExists($table)){
// The table exists, run the query
$query = #mysql_query($q);
if($query){
// If the query returns >= 1 assign the number of rows to numResults
$this->numResults = mysql_num_rows($query);
// Loop through the query results by the number of rows returned
for($i = 0; $i < $this->numResults; $i++){
$r = mysql_fetch_array($query);
$key = array_keys($r);
for($x = 0; $x < count($key); $x++){
// Sanitizes keys so only alphavalues are allowed
if(!is_int($key[$x])){
if(mysql_num_rows($query) > 1){
$this->result[$i][$key[$x]] = $r[$key[$x]];
}else if(mysql_num_rows($query) < 1){
$this->result = null;
}else{
$this->result[$key[$x]] = $r[$key[$x]];
}
}
}
}
return true; // Query was successful
}else{
array_push($this->result,mysql_error());
return false; // No rows where returned
}
}else{
return false; // Table does not exist
}
}
How would I be able to perform an SQL injection?
EDIT:
The value is received via browser using $_GET['id']. There is, in fact, a second value which is not used in an SQL query but a switch statement. So, the full request looks like this:
http://localhost/api/view.php?rsvp=<status>&id=<id>
That may help.
EDIT 2:
It may have been important to mention that the ids in question are in fact GUIDs, not numeric values. I ran all queries in the comments so far with a proper ID. Here are some results:
http://localhost/api/view.php?id=62FD23D8-B6C0-03F1-D45A-C9AC33C91774%27;%20drop%20table%20users;-- => array(1) { [0]=> string(166) "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 'drop table users;--'' at line 1" }
http://localhost/api/view.php?id=62FD23D8-B6C0-03F1-D45A-C9AC33C91774%27;select%20*%20from%20invitations;%27 => array(1) { [0]=> string(179) "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 'select * from invitations;''' at line 1" }
These following lines are the entirety of the code that makes use of $id:
// ...
if(isset($_GET['id'])) {
$id = $_GET['id'];
$db->select('invitations','Replied, Response, Registered',null,"Id = '".$id."'");
$res = $db->getResult();
// ...
}
Just the fact alone that some specific input results in a MySQL syntax error is a proof that the user input has some unintended influence on the SQL syntax, which means SQL injection is possible.
But the exploitation of this SQL injection is a different chapter. And MySQL, or more precisely PHP’s MySQL extension, does not support the execution of multiple statements with mysql_query by default:
mysql_query() sends a unique query (multiple queries are not supported) […]
So the classic example of dropping a table won’t work and you’re limited to the capabilities of the current statement and the allowed syntax elements from the injection point on.
In your specific example, the SELECT limits you to
reading arbitrary data from the database that the MySQL user has access to
reading files using the LOAD_FILE function
writing files using the INTO … syntax
For reading arbitrary data, a UNION would be the best choice as the results seem to get reflected back to the user. All you have to ensure is that the resulting SQL is valid, which means your UNION must to have three columns (i. e., Replied, Response, and Registered from the existing SELECT):
' UNION SELECT '1','2','3
The resulting statement would then look like:
SELECT Replied, Response, Registered FROM invitations WHERE Id = '' UNION SELECT '1','2','3'
You now can replace the additionally selected values by your own expressions (including LOAD_FILE) or sub-queries.

PHP PDO - Bind number of variables dynamically

I'm trying to add a search feature on my site there are 4 different inputs the user can use although they might not use all 4. I'm appending to my sql query depending on which inputs they fill in;
$query = "SELECT * FROM cars WHERE status = 2 ";
if($_GET['ref']){
$query .= " AND ref = :ref";
}
if($_GET['doors']){
$query .= " AND doors = :doors";
}
if($_GET['wheels']){
$query .= " AND wheels = :wheels";
}
if($_GET['location']){
$query .= " AND location = :location";
}
$query .= ")";
$adverts = Singlequery ($query, array(
'ref' => $_GET['ref'],
'doors' => $_GET['doors'],
'wheels' => $_GET['wheels'],
'location' => $_GET['location']
), $conn);
This is my query I'm using -
function query($query, $bindings, $conn)
{
$stmt = $conn->prepare($query);
$stmt->execute($bindings);
return $stmt;
}
I'm getting the error -
PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
I think its expecting all 4 inputs to be used and therefore wants 4 bound variables.
First of all you have a missing parenthesis in your query. You are closing it but not opening.
You should create your variable array also in if clauses as :
$query = "SELECT * FROM cars WHERE status = 2 ";
$data=array();
if($_GET['ref']){
$query .= " AND ref = :ref";
$data['ref']=$_GET['ref'];
}
if($_GET['doors']){
$query .= " AND doors = :doors";
$data['doors']=$_GET['doors'];
}
if($_GET['wheels']){
$query .= " AND wheels = :wheels";
$data['wheels']=$_GET['wheels'];
}
if($_GET['location']){
$query .= " AND location = :location";
$data['location']=$_GET['location'];
}
$adverts = Singlequery($query, $data, $conn);
Try to use ? instead the :alias format.
Maybe you can try to say "if this variable is empty, set it to Null" Then the variables that stay empty will be Null instead of undefined.
Could it be because you always feed it an array of size four as to bind, while your query string sometimes won't have as many due to the if statements, hence the error message?

Error received from database was #1064 - PHP & MySQL

I have a simple MySQL query that I use in PHP but it gives me this error;
Database query failed. Error received from database was #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 'NULL' at line 3 for the query: SELECT *
FROM mantis_user_table
WHERE email LIKE '%me%'.
$t_user_table = db_get_table( 'mantis_user_table' );
$temp_mail = '%' . $p_email . '%';
$query = "SELECT * FROM $t_user_table WHERE email LIKE '{$temp_mail}'";
$result = db_query_bound( $query, Array( $p_realname ) );
The thing I can not understand is, when I run it in phpmyadmin, it gives me the correct values.
So can you please help me with this situation ?
Thank you
EDIT :
This is the code that I use while editing :
$File = "c:/YourFile.txt";
$Handle = fopen($File, 'w');
$Data = $query;
fwrite($Handle, $Data);
fclose($Handle);
Here you can see the query that I get when I write :
SELECT * FROM mantis_user_table WHERE email LIKE '%meh%'
And this query normally gives me some results in phpmyadmin , now I dont have any result on web site
And if you want this is the rest of the code that returns the id of the selected item:
$result = db_query_bound( $query, Array( $temp_mail ) );
if( 0 == db_num_rows( $result ) ) {
return false;
} else {
$row = db_fetch_array( $result );
user_cache_database_result( $row );
return $row['id'];
}
try making
$query = 'SELECT * FROM $t_user_table WHERE email LIKE "{$temp_mail}"';
(some versions of mysql don't recognize ' symbol)

Categories