Both codes does the same Job, But which one is better to use and when to use?
PHP method
$names = [];
$Query = "SELECT DISTINCT name FROM names";
$stmt = $conn->prepare($Query);
$stmt->execute();
while ($name = $stmt->fetch()) {
$names[] = $name['epic'];
}
$names = implode(',', $names);
SQL method
$Query = "SELECT GROUP_CONCAT(DISTINCT name) AS names FROM names";
$stmt = $conn->prepare($Query);
$stmt->execute();
$row = $stmt->fetch();
$names = $row['names'];
It depends. GROUP_CONCAT() has the limit which is imposed by group_concat_max_len system option, and its length is 1024 by default (more info).
Also, it will concatenate non-null values, which you may want to handle in a different way, rather than just ignoring them.
Related
I am trying to make a search key feature. But I am not getting any result with the following query.
public function SearchKey($key,$userid)
{
$key = mysqli_real_escape_string($this->db, $key);
$userid = mysqli_real_escape_string($this->db, $userid);
$query = mysqli_query($this->db,"SELECT * FROM posts WHERE
MATCH(theKey) AGAINST('$key' IN NATURAL LANGUAGE MODE)
AND uid = '$userid' ORDER BY sgq_id LIMIT 5") or die(mysqli_error($this->db));
while($row=mysqli_fetch_array($query)) {
$data[]=$row;
}
if(!empty($data)) {
return $data;
}
}
Then fetch,
$search = $Data->SearchKey($key, $userid);
if($search){
foreach($search as $data){
echo $data['theKey'];
}
}
For example if I search OK005 then I can not get any results. I tried Full-text Search functions https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html
Anyone can help me here, what I am missing ?
You're using single quotes to pass your variables. These will not be expanded in your query. You're better off using a prepared statement, and use parameter/value bindings to pass the variables. This will also solve the problem of SQL injection that your code appears to be vulnerable to.
You can try something like:
// Replace comment with appropriate connection data.
$pdo = new PDO(/* your DSN etc. */);
// Your query.
$sql =
'SELECT * FROM posts WHERE ' .
'MATCH(theKey) AGAINST(? IN NATURAL LANGUAGE MODE) ' .
'AND uid = ? ORDER BY sgq_id LIMIT 5';
// Create prepared statement from query.
$statement = $pdo->prepare($sql);
// Bind the values and enforce data type.
$statement->bindValue(1, $key, PDO::PARAM_STR);
$statement->bindValue(2, $userid, PDO::PARAM_INT);
// Run query.
$statement->execute();
// Get query results.
$rows = $statement->fetchAll();
// Your magic ...
I am using the method below to get values from the database (from the "$column" column) and it is working as intended but i would like to know the correct way to implement the "$column" variable that is added in the SELECT statement, so as to be as safe as possible from injection (either by preparing with a ?-type placeholder or by properly escaping). What would be the most modern and safe approach?
NOTE: $qry->bind_param("ss",$column,$rowName); with 2 ? placeholders doesn't work.
$column = $_POST['column'];
$rowName = $_POST['rowName'];
$qry = $connection->prepare("SELECT $column FROM database_name WHERE row_name=?");
$qry->bind_param("s",$rowName);
$qry->execute();
$result = $qry->get_result();
$column = $_POST['column'];
$rowName = $_POST['rowName'];
$qry = $connection->prepare("SELECT * FROM database_name WHERE row_name=?");
$qry->bind_param("s",$rowName);
$qry->execute();
$result = $qry->get_result();
$value = $result[$column];
My PHP looks like this:
$diagSel = $_POST['diagSel'];
$search_crit = $_POST['criteria']; //this is an entry like "85054,85206" (no quotes)
$sql1 = "SELECT * FROM `myTable` where`Diagnosis` = :diagnosis and `zip_code` in (:placeHolder) group by `Provider Number`";
$stmt = $dbh->prepare($sql1);
$stmt->bindParam(':diagnosis', $diagSel, PDO::PARAM_STR);
$stmt->bindParam(':placeHolder', $search_crit, PDO::PARAM_STR);
$stmt->execute();
$result1 = $stmt->fetchAll(PDO::FETCH_ASSOC);
header('Content-type: application/json');
echo json_encode($result1);
Here's the problem...if the user enters multiple ZIP Codes (passed in criteria) that are comma separated, this ECHOs nothing. If they enter a single ZIP Code, it returns exactly what I'd expect.
Is there a way to pass a comma separated value by PDO such as 85054,85206 using prepared statements?
Thanks.
It is not, I'd recommend something like this:
$diagSel = $_POST['diagSel'];
$search_crit = $_POST['criteria'];
$list = explode(',', $search_crit);
array_map(array($dbh, 'quote'), $list);
$sql1 = sprintf('
SELECT *
FROM `myTable`
WHERE `Diagnosis` = :diagnosis
AND `zip_code` IN (%s)
GROUP BY `Provider Number`', implode(',', $list));
$stmt = $dbh->prepare($sql1);
$stmt->bindParam(':diagnosis', $diagSel, PDO::PARAM_STR);
$stmt->execute();
$result1 = $stmt->fetchAll(PDO::FETCH_ASSOC);
header('Content-type: application/json');
echo json_encode($result1);
You can't use bindpram twice if you want to add multiple values to the SQL query have an array in the exec command to add in all the variables
Not sure how I can do this. Basically I have variables that are populated with a combobox and then passed on to form the filters for a MQSQL query via the where clause. What I need to do is allow the combo box to be left empty by the user and then have that variable ignored in the where clause. Is this possible?
i.e., from this code. Assume that the combobox that populates $value1 is left empty, is there any way to have this ignored and only the 2nd filter applied.
$query = "SELECT * FROM moth_sightings WHERE user_id = '$username' AND location = '$value1' AND english_name = $value2 ";
$result = mysql_query($query) or die(mysql_error());
$r = mysql_numrows($result);
Thanks for any help.
C
Use
$where = "WHERE user_id = '$username'";
if(!empty($value1)){
$where .= "and location = '$value1'";
}
if(!empty($value2 )){
$where .= "and english_name= '$value2 '";
}
$query = "SELECT * FROM moth_sightings $where";
$result = mysql_query($query) or die(mysql_error());
$r = mysql_numrows($result);
Several other answers mention the risk of SQL injection, and a couple explicitly mention using prepared statements, but none of them explicitly show how you might do that, which might be a big ask for a beginner.
My current preferred method of solving this problem uses a MySQL "IF" statement to check whether the parameter in question is null/empty/0 (depending on type). If it is empty, then it compares the field value against itself ( WHERE field1=field1 always returns true). If the parameter is not empty/null/zero, the field value is compared against the parameter.
So here's an example using MySQLi prepared statements (assuming $mysqli is an already-instantiated mysqli object):
$sql = "SELECT *
FROM moth_sightings
WHERE user_id = ?
AND location = IF(? = '', location, ?)
AND english_name = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('ssss', $username, $value1, $value1, $value2);
$stmt->execute();
(I'm assuming that $value2 is a string based on the field name, despite the lack of quotes in OP's example SQL.)
There is no way in MySQLi to bind the same parameter to multiple placeholders within the statement, so we have to explicitly bind $value1 twice. The advantage that MySQLi has in this case is the explicit typing of the parameter - if we pass in $value1 as a string, we know that we need to compare it against the empty string ''. If $value1 were an integer value, we could explicitly declare that like so:
$stmt->bind_param('siis', $username, $value1, $value1, $value2);
and compare it against 0 instead.
Here is a PDO example using named parameters, because I think they result in much more readable code with less counting:
$sql = "SELECT *
FROM moth_sightings
WHERE user_id = :user_id
AND location = IF(:location_id = '', location, :location_id)
AND english_name = :name";
$stmt = $pdo->prepare($sql);
$params = [
':user_id' => $username,
':location_id' => $value1,
':name' => $value2
];
$stmt->execute($params);
Note that with PDO named parameters, we can refer to :location_id multiple times in the query while only having to bind it once.
if ( isset($value1) )
$query = "SELECT * FROM moth_sightings WHERE user_id = '$username' AND location = '$value1' AND english_name = $value2 ";
else
$query = "SELECT * FROM moth_sightings WHERE user_id = '$username' AND english_name = $value2 ";
But, you can also make a function to return the query based on the inputs you have.
And also don't forget to escape your $values before generating the query.
1.) don't use the simply mysql php extension, use either the advanced mysqli extension or the much safer PDO / MDB2 wrappers.
2.) don't specify the full statement like that (apart from that you dont even encode and escape the values given...). Instead use something like this:
sprintf("SELECT * FROM moth_sightings WHERE 1=1 AND %s", ...);
Then fill that raw query using an array holding all values you actually get from your form:
$clause=array(
'user_id="'.$username.'"',
'location="'.$value1.'"',
'english_name="'.$value2.'"'
);
You can manipulate this array in any way, for example testing for empty values or whatever. Now just implode the array to complete the raw question from above:
sprintf("SELECT * FROM moth_sightings WHERE 1=1 AND %s",
implode(' AND ', $clause) );
Big advantage: even if the clause array is completely empty the query syntax is valid.
First, please read about SQL Injections.
Second, $r = mysql_numrows($result) should be $r = mysql_num_rows($result);
You can use IF in MySQL, something like this:
SELECT * FROM moth_sightings WHERE user_id = '$username' AND IF('$value1'!='',location = '$value1',1) AND IF('$value2'!='',english_name = '$value2',1); -- BUT PLEASE READ ABOUT SQL Injections. Your code is not safe.
Sure,
$sql = "";
if(!empty($value1))
$sql = "AND location = '{$value1}' ";
if(!empty($value2))
$sql .= "AND english_name = '{$value2}'";
$query = "SELECT * FROM moth_sightings WHERE user_id = '$username' {$sql} ";
$result = mysql_query($query) or die(mysql_error());
$r = mysql_numrows($result);
Be aware of sql injection and deprecation of mysql_*, use mysqli or PDO instead
I thought of two other ways to solve this:
SELECT * FROM moth_sightings
WHERE
user_id = '$username'
AND location = '%$value1%'
AND english_name = $value2 ";
This will return results only for this user_id, where the location field contains $value1. If $value1 is empty, this will still return all rows for this user_id, blank or not.
OR
SELECT * FROM moth_sightings
WHERE
user_id = '$username'
AND (location = '$value1' OR location IS NULL OR location = '')
AND english_name = $value2 ";
This will give you all rows for this user_id that have $value1 for location or have blank values.
function fetchbyId($tableName,$idName,$id){
global $connection;
$stmt = mysqli_prepare($connection, 'SELECT * FROM ? WHERE ? = ?');
var_dump($stmt);
mysqli_stmt_bind_param($stmt,'s',$tableName);
mysqli_stmt_bind_param($stmt,'s',$idName);
mysqli_stmt_bind_param($stmt,'i',$id);
$stmt = mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($name,$id);
$fetchArray = array();
while($row = mysqli_stmt_fetch($stmt)){
$fetchArray[] = $row;
}
return $fetchArray;
}
can i use the place holders for table names to or is this only possible for table columns?
No, it only accepts values (i.e.: not columns, table names, schema names and reserved words), as they will be escaped. You can do this though:
$sql = sprintf('SELECT * FROM %s WHERE %s = ?', $tableName, $idName);
$stmt = mysqli_prepare($connection, $sql);
mysqli_stmt_bind_param($stmt,'i',$id);
No, you can't. Table and column names are syntax, values are data. Syntax cannot be parameterized.
The table/column name can safely be inserted into the string directly, because they come from a proven, limited set of valid table/column names (right?). Only user-supplied values should be parameters.
function fetchbyId($tableName,$idName,$id){
global $connection;
$stmt = mysqli_prepare($connection, "SELECT * FROM $tableName WHERE $idName = ?");
mysqli_stmt_bind_param($stmt,'i',$id);
$stmt = mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($name,$id);
$fetchArray = array();
while($row = mysqli_stmt_fetch($stmt)){
$fetchArray[] = $row;
}
return $fetchArray;
}