I'm trying to prevent my query from being injected with SQL injection by using a prepared statement. but how to implement prepared statement into array_push()?
here I use array push for custom search purposes.
Here is the code snippet that I have now.
public function getDataTable(Request $req) {
$start = $req->start;
$length = $req->length;
$draw = $req->draw;
$order = $req->order;
$type = '';
$where = $this->storeParams($req);
$data = $this->getData($where, $start, $length, $order, $type);
.
.
.
.
$output = [
'draw' => (int) $draw,
'recordsTotal' => $total,
'recordsFiltered' => $filtered,
'data' => $data,
];
return json_encode($output);
}
public function storeParams(Request $req) {
$param = [];
$start_date = date('Y-m-d');
$end_date = date('Y-m-d');
if (!empty($req->studentid)) {
array_push($param, 'studentid LIKE \'' . $req->studentid . '\'');
}
if (!empty($req->studentnm)) {
array_push($param, 'studentnm LIKE \'' . $req->studentnm . '%\'');
}
if (!empty($start_date) && !empty($end_date)) {
array_push($param, "entrydate between '" . $start_date . "' and '" . $end_date . "'");
}
if (count($param) > 0) {
$where = implode(' and ', $param);
} else {
$where = "1";
}
return $where;
}
public function getData($where, $start = null, $length = null, $order = null, $type = null) {
.
.
.
.
$dataSet = DB::connection('mysql5')->table('tbl_datastudent')
->selectRaw("studentid, stuidentnm, address, entrydate, payment, paymentdate")
->whereRaw($where);
.
.
.
.
}
how do i apply the prepared statement into the storeParams() function? anybody can guide or help me?
updated
i'm already found the answer
->when($request->studentid, function ($q) use ($request) {
$q->whereRaw('studentid LIKE ?', ['%'.$request->studentid.'%']);
})
Related
I began to write a generic class for SELECT queries that looks like this:
class DbQuery
{
private $database;
public function __construct()
{
$db_config = array(
"type" => "mysql",
"host" => "localhost",
"port" => "3306",
"charset" => "utf8",
"db" => "dbname",
"user" => "user",
"password" => "topsecret"
);
$this->database = DatabaseFactory::getFactory()->getConnection($db_config);
}
public function Select($keys = array("*"), $table, $whereClauseArray = null, $orderValues = null, $orderDirection = null, $limitIndex = null, $limitLength = null)
{
$statement = "SELECT " . implode(',', $keys) . " FROM " . $table;
if (!empty($whereClauseArray)) {
$whereClauseString = " WHERE ";
$i = 0;
foreach ($whereClauseArray as $whereClause) {
if ($i > 0) {
$whereClauseString .= " " . $whereClause['link'] . " ";
}
$whereClauseString .= $whereClause['key'] . " " . $whereClause['operand'] . " :" . $whereClause['key'] . "_" . $i;
$i++;
}
$statement .= $whereClauseString;
}
if (!empty($orderValues)) {
$orderClause = " ORDER BY ";
foreach ($orderValues as $order) {
$orderClause .= $order . ", ";
}
$orderClause = substr($orderClause, 0, -2);
$statement .= $orderClause . " " . $orderDirection;
}
if ($limitIndex != null && $limitLength != null) {
$statement .= " LIMIT " . $limitIndex . "," . $limitLength;
}
$query = $this->database->prepare($statement . ";");
$file = $_SERVER["DOCUMENT_ROOT"] . '/../db.log';
$current = file_get_contents($file);
$current .= date("Y-m-d H:i:s", time()) . " => ";
$current .= "Statement: " . $statement . "\n";
file_put_contents($file, $current);
$j = 0;
foreach ($whereClauseArray as $whereClause) {
$keystring = ":" . $whereClause['key'] . "_" . $j;
$bindValue = trim(strip_tags($whereClause['value']));
$query->bindValue($keystring, $bindValue);
$file = $_SERVER["DOCUMENT_ROOT"] . '/../db.log';
$current = file_get_contents($file);
$current .= date("Y-m-d H:i:s", time()) . " => ";
$current .= "BindValue: " . $keystring . " -> " . trim(strip_tags($whereClause['value'])) . "\n";
file_put_contents($file, $current);
$j++;
}
// $query->execute();
if ($keys === "count(*)") {
return $query->fetchColumn(0);
} else {
return $query->fetchAll();
}
}
}
I call the function like that:
$obj_artikel_startseite = new DbQuery();
$obj_artikel_startseite->Select(array("*"), "psartikel", array(array("link" => "AND", "key" => "status", "value" => "freigeschaltet", "operand" => "="), array("link" => "OR", "key" => "status", "value" => "reserviert", "operand" => "=")), array("id"), "DESC", 0, 3)) {
As long as I leave the execution commented, I get a proper output in my db.log file:
2022-10-23 19:35:51 => Statement: SELECT * FROM psartikel WHERE status = :status_0 OR status = :status_1 ORDER BY id DESC
2022-10-23 19:35:51 => BindValue: :status_0 -> freigeschaltet
2022-10-23 19:35:51 => BindValue: :status_1 -> reserviert
But when I try to execute the prepared statement with binded values, it leads to an endless loop. I donĀ“t understand why.
Regards
Edit: Endless loop means the execution limit exceeds and the output in my log is about thousands, indentical entries...
I am trying to build a search query based on the input from users, but I am having problems with the AND and WHERE keywords. Here is the code:
if (isset($_POST['submitBtn'])) {
$gender = $_POST['gender'];
$level = $_POST['level'];
$status = $_POST['status'];
$query = 'SELECT * FROM candidate ';
$where = array();
$criteria = array('gender' => $gender, 'level' => $level, 'status' => $status);
foreach ($criteria as $key => $value) {
if ($value !== 'all') {
$where[] = $key . ' = ' . $value;
}
}
}
The output looks like this:
Array
(
[0] => gender = masculine
[1] => level = low
[2] => status = future
)
If no option is selected, it defaults to 'all' and it is excluded from the $where[].
I need to achieve this, or anything similar:
Array
(
[0] => WHERE gender = masculine
[1] => AND level = low
[2] => AND status = future
)
The WHERE must be appended only if one or more options have been selected and the AND must be appended only if two or more options have been selected.
In the code I am using I have 9 search inputs. To keep it clear I only displayed three in the snippet. Can you please help me figure this out?
Try this:I think you need the whereClause in string not in array,here you can choose any one from two and remove the other one.
<?php
$where=array();$flag=0;// use flag to identify the where/and
$whereClause="";
$criteria = array('gender' => "masculine", 'level' => "low", 'status' => "future");
foreach ($criteria as $key => $value) {
if ($value !== 'all') {
if($flag == 0){
$where[] = " WHERE " .$key . ' = ' . $value;//if you need array
$whereClause='WHERE '.$key . ' = "' . $value.'"';//if you need string
}else{
$where[] = " AND " .$key . ' = ' . $value;
$whereClause .=' AND '.$key . ' = "' . $value.'"';
}
$flag++;
}
}
echo "<pre>";
print_r($where);
echo "</pre>";
echo $whereClause;
?>
You can do this :
$query = 'SELECT * FROM candidate ';
$where='';
$criteria = array('gender' => $gender, 'level' => $level, 'status' => $status);
foreach ($criteria as $key => $value) {
if ($value !== 'all') {
if($where=='')
$where='WHERE '.$key . ' = ' . $value;
else
$where.=' AND '.$key . ' = ' . $value;
}
}
$query.=$where; //final query
You can use simple switch statement too
<?
if (isset($_POST['submitBtn'])) {
$gender = $_POST['gender'];
$level = $_POST['level'];
$status = $_POST['status'];
$query = 'SELECT * FROM candidate ';
$where = array();
$criteria = array('gender' => $gender, 'level' => $level, 'status' => $status);
foreach ($criteria as $key => $value)
{
if ($value !== 'all')
{
switch ($key)
{
case 1:
{
$query = " WHERE " .$key . ' = ' . $value;
break;
}
case 2:
{
$query = " AND " .$key . ' = ' . $value;
break;
}
case 3:
{
$query = " AND " .$key . ' = ' . $value;
break;
}
}
$where[] = $query;
}
}
}
You need to put one incrementer ($inc) and then put the conditions as:
$inc=1;
foreach ($criteria as $key => $value) {
if ($value !== 'all') {
if($inc==1){
$where[] = 'Where '.$key . ' = ' . $value.'';
}else{
$where[] = 'AND '.$key . ' = ' . $value.'';
}
$inc++;
}
}
In My view there is one more clean way of achiving this:
if (isset($_POST['submitBtn'])) {
$gender = $_POST['gender'];
$level = $_POST['level'];
$status = $_POST['status'];
$query = 'SELECT * FROM candidate ';
$where = array("Where 1=1");
$criteria = array('gender' => $gender, 'level' => $level, 'status' => $status);
foreach ($criteria as $key => $value) {
if ($value !== 'all') {
$where[] = 'AND '.$key . ' = ' . $value.' ';
}
}
}
how i can make a insert using this fuctions
I m learning php, as using this functions (mysqli abstract) but after update wont work any more.
/** insert data array */
public function insert(array $arr)
{
if ($arr)
{
$q = $this->make_insert_query($arr);
$return = $this->modifying_query($q);
$this->autoreset();
return $return;
}
else
{
$this->autoreset();
return false;
}
}
complement
/** insert query constructor */
protected function make_insert_query($data)
{
$this->get_table_info();
$this->set_field_types();
if (!is_array(reset($data)))
{
$data = array($data);
}
$keys = array();
$values = array();
$keys_set = false;
foreach ($data as $data_key => $data_item)
{
$values[$data_key] = array();
$fdata = $this->parse_field_names($data);
foreach ($fdata as $key => $val)
{
if (!$keys_set)
{
if (isset($this->field_type[$key]))
{
$keys[] = '`' . $val['table'] . '`.`' . $val['field'] . '`';
}
else
{
$keys[] = '`' . $val['field'] . '`';
}
}
$values[$data_key][] = $this->escape($val['value'], $this->is_noquotes($key), $this->field_type($key), $this->is_null($key),
$this->is_bit($key));
}
$keys_set = true;
$values[$data_key] = '(' . implode(',', $values[$data_key]) . ')';
}
$ignore = $this->ignore ? ' IGNORE' : '';
$delayed = $this->delayed ? ' DELAYED' : '';
$query = 'INSERT' . $ignore . $delayed . ' INTO `' . $this->table . '` (' . implode(',', $keys) . ') VALUES ' . implode(',',
$values);
return $query;
}
before update this class i used to insert data like this
$db = Sdba::table('users');
$data = array('name'=>'adam');
$db->insert($data);
this method of insert dont works on new class.
if i try like this i got empty columns and empty values.
thanks for any help
complete class download http://goo.gl/GK3s4E
Try using set instead of insert:
$users = Sdba::table('users');
$user['name'] = 'Alvaro';
$users->set($user);
This is a bit confusing for me, so I will try to explain it the best I can.
I am running update but nothing is happens.
This is the query which I get:
"UPDATE users SET name = :name, surname = :surname WHERE name = :name AND surname = :surname"
I start the query like this:
$data = ['name' => 'Sasha', 'surname' => 'M'];
$user = $users->where(['name' => 'TestName', 'surname' => 'TestSurname'])->update($data);
This is the update function:
public function update($data)
{
$fields = explode(',', $this->prepareFields($data));
$values = explode(',', $this->prepareValues($data));
$i = 0;
$count = count($fields);
$query = "UPDATE {$this->_tablename} SET ";
for($i; $i < $count; $i++):
$query .= $fields[$i] . " = " . $values[$i] . ',';
endfor;
$query = rtrim($query, ',');
$query .= " WHERE " . rtrim($this->_dbWhere, ' AND ');
$this->query($query);
$this->bindData($data);
$this->_dbBind = call_user_func_array('array_merge', $this->_dbBind);
$this->bindData($this->_dbBind);
$this->execute();
return $this->lastInsertId();
}
Where function:
public function where($field, $value = null)
{
if(!is_array($field)):
$this->_dbWhere .= $field . ' = :' . $field . ' AND ';
$this->_dbBind[] = [$field => $value];
else:
foreach($field as $key => $value):
$this->_dbWhere .= $key . ' = :' . $key . ' AND ';
$this->_dbBind[] = [$key => $value];
endforeach;
endif;
return $this;
}
Bind data function:
public function bindData($data)
{
foreach ($data as $key => $value) :
$this->bind(':' . $key, $value);
endforeach;
}
public function bind($param, $value, $type = null){
if (is_null($type)) {
switch (true) {
case is_int($value):
$type = \PDO::PARAM_INT;
break;
case is_bool($value):
$type = \PDO::PARAM_BOOL;
break;
case is_null($value):
$type = \PDO::PARAM_NULL;
break;
default:
$type = \PDO::PARAM_STR;
}
}
$this->stmt->bindValue($param, $value, $type);
}
Prepare fields and prepare values:
public function prepareFields($data)
{
return $fields = implode(', ', array_keys($data));
}
public function prepareValues($data)
{
$values = implode(', :', array_keys($data));
return ':' . $values;
}
Query function:
public function query($query){
$this->stmt = $this->handler->prepare($query);
}
The crux of this is that you use the same placeholder :fieldname in the WHERE clause and in the SET portion of the statement. You do need to correct other small issues raised here, but a simple solution is to make this change in the where() function:
if(!is_array($field)):
// make up a placeholder name distinct from the one used in SET clause
$field_placeholder = ":where_".$field
$this->_dbWhere .= $field . ' = ' . $field_placeholder . ' AND ';
$this->_dbBind[] = [$field_placeholder => $value];
else:
I was wondering how I could make a general function for SELECT mysql queries from my SelectQuery object in PHP. SelectQuery extends Query, which means it inherits the database connection, a realescape method (which is mysqli_real_escape_string()), and a query method which executes the query. Besides that, it also gets a protected variable called _sql, which is the SQL the query() method passes to the database. And it also gets a protected variable called _table, which contains the (escaped) name of the table it's working on.
My code:
public function select($columns = array('*'), $known = null, $limit = null, $offset = null, $orderby = null, $asc = true) {
if (!is_array($columns)) {
new Error('Parameter is not an array.');
return;
}
$select = '';
foreach($columns as $column) {
$select .= (($select != '')?', ':'') . '`' . $this->realescape($column) . '`';
}
$conditions = '';
if (is_array($known)) {
foreach($known as $column => $value) {
$conditions .= (($conditions != '')?' AND ':'WHERE ') . '`' . $this->realescape($column) . '` = ' . ((is_string($value))?'\'':'') . $this->realescape($value) . ((is_string($value))?'\'':'');
}
}
$domain = '';
if ($limit !== null) {
$domain = 'LIMIT ' . $this->realescape($limit);
if ($offset !== null) {
$domain .= ' OFFSET = ' . $this->realescape($offset);
}
}
$order = '';
if ($orderby !== null) {
$order = 'ORDER BY `' . $this->realescape($orderby) . '` ' . (($asc)?'ASC':'DESC');
}
$this->_sql = 'SELECT ' . $select . ' FROM `' . $this->_table . '`';
if ($conditions != '') {
$this->_sql .= ' ' . $conditions;
}
if ($domain != '') {
$this->_sql .= ' ' . $domain;
}
if ($order != '') {
$this->_sql .= ' ' . $order;
}
return $this->query();
}
The $known variable might be set, if set it should be an array which contains all the 'known' elements of the rows we are selecting.
My question: How can I make this so that conditions such as
age < 18, or date > 5120740154 are easily made?
Also, if you think the way I'm making this work is wrong, please say so.
Thanks in advance
Dynamically build WHERE conditions that can use any operators
Create a $where array that holds your where conditions.
$where = array (
'age <' => 18,
'date >' => 5120740154
);
You can build that into your SQL query using a function like this:
private function buildWhereConditions($where) {
$conditions = 'WHERE 1=1';
/*1=1 is just so you can easily append ANDs */
foreach ($where as $key => $value) {
$conditions .= " AND $key $value ";
}
return $conditions;
}
This will return the where conditions to be appended to your query:
WHERE 1=1 AND age < 18 AND date > 5120740154