Correction function calculation in your online ratings - php

I need your help on this php function.
The function takes the data from the db, does the account of the score and exports it. In practice the score must be calculated for both the buyer and for the seller ($type) but when I go to export I only have one of the buyers. The code in question is below. Thanks in advance for the help.
function shop_get_ratings($user_id, $type = 'seller'){
$type = strtolower($type);
$valid = array('seller','buyer');
if( !in_array($type, $valid)){
return false;
}
$conn = getConnection();
$sql = 'SELECT AVG(i_%s_score) as %s_rating FROM %st_shop_transactions WHERE fk_i_user_id = %d AND i_%s_score IS NOT NULL';
$rs = $conn->osc_dbFetchResults(sprintf($sql,$type,$type, DB_TABLE_PREFIX, $user_id, $type));
$seller_r = 0;
if( false !== $rs && isset($rs[0]['seller_rating']) && !is_null($rs[0]['seller_rating']) ){
$seller_r = (int)$rs[0]['seller_rating'];
}
$sql = 'SELECT COUNT(*) as rating_count FROM %st_shop_transactions WHERE fk_i_user_id = %d AND i_%s_score IS NOT NULL';
$rs = $conn->osc_dbFetchResults(sprintf($sql, DB_TABLE_PREFIX, $user_id, $type));
$seller_r_c = 0;
if( false !== $rs && isset($rs[0]['rating_count']) && !is_null($rs[0]['rating_count']) ){
$seller_r_c = (int)$rs[0]['rating_count'];
}
$percentage = 0;
if( $seller_r > 0 ){
$percentage =($seller_r/5)*100;
}
$stats = array(
'average_rating' => (int)$seller_r,
'rating_percentege' => (float)$percentage,
'rating_count' => (int)$seller_r_c,
);
View::newInstance()->_exportVariableToView($type.'_ratings', $stats);
return $stats;
}

From reading the code, it looks like you should get a rating for the seller ok, but it's the buyer who ends up with a 0 rating.
This is because in the line $sql = 'SELECT AVG(i_%s_score) as %s_rating you are inserting $type in to the query to have the field named seller_type or buyer_type, depending on the type of rating you're trying to get with the function.
However when querying the result set you are explicitly looking for the field named seller_rating. This field won't be set when $type is buyer, so $seller_r will always be 0.
The simplest fix here is likely to name the field as something like avg_rating in the sql, with no $type-dependent var name injection. So, something like:
$sql = 'SELECT AVG(i_%s_score) as avg_rating
FROM %st_shop_transactions
WHERE fk_i_user_id = %d
AND i_%s_score IS NOT NULL';
$rs = $conn->osc_dbFetchResults(
sprintf($sql, $type, DB_TABLE_PREFIX, $user_id, $type)
);
$seller_r = 0;
if (false !== $rs
&& isset($rs[0]['avg_rating'])
&& !is_null($rs[0]['avg_rating'])
){
$seller_r = (int)$rs[0]['avg_rating'];
}

Related

Ambiguous column in Codeigniter Datatables server side

I'm working on a system that has several server-side datatables but i facing issues with 2 joins when i try to order de columns.
I receive the following message when try to sort the columns:
Query error: Column 'notes' in order clause is ambiguous - Invalid query: SELECT *
FROM `tbl_project`
LEFT JOIN `tbl_client` ON `tbl_project`.`client_id`=`tbl_client`.`client_id`
LEFT JOIN `tbl_account_details` ON `tbl_project`.`created_by` = `tbl_account_details`.`user_id`
LEFT JOIN `tbl_notes` ON `tbl_project`.`notes` = `tbl_notes`.`notes_id`
WHERE `tbl_project`.`client_id` = '100'
ORDER BY `notes` DESC
LIMIT 10
This is the code with my query:
$id = $this->input->post("client_id");
$client_details = get_row('tbl_client', array('client_id' => $id));
$draw = intval($this->input->post("draw"));
$start = intval($this->input->post("start"));
$length = intval($this->input->post("length"));
$order = $this->input->post("order");
$search= $this->input->post("search");
$search = $search['value'];
$col = 0;
$dir = "";
if(!empty($order))
{
foreach($order as $o)
{
$col = $o['column'];
$dir= $o['dir'];
}
}
if($dir != "desc" && $dir != "desc")
{
$dir = "desc";
}
$valid_columns = array(
0=>'project_id',
1=>'client',
2=>'fullname',
3=>'notes',
4=>'origen',
5=>'end_date',
6=>'project_status',
7=>'action',
);
if(!isset($valid_columns[$col]))
{
$order = null;
}
else
{
$order = $valid_columns[$col];
}
if($order !=null)
{
$this->db->order_by($order, $dir);
}
$searchQuery = "";
if($search != ''){
$searchQuery = " (tbl_project.project_id like'%".$search."%' OR tbl_project.end_date like'%".$search."%' OR tbl_project.project_status like'%".$search."%' OR tbl_notes.notes like'%".$search."%' OR tbl_notes.eco like'%".$search."%' OR tbl_account_details.origen like'%".$search."%' OR tbl_client.name like'%".$search."%') ";
}
$this->db->select('*');
$this->db->from('tbl_project');
$this->db->join('tbl_client', 'tbl_project.client_id=tbl_client.client_id','left');
$this->db->join('tbl_account_details', 'tbl_project.created_by = tbl_account_details.user_id','left');
$this->db->join('tbl_notes', 'tbl_project.notes = tbl_notes.notes_id','left');
$this->db->where('tbl_project.client_id', $client_details->client_id);
if($searchQuery != '')
$this->db->where($searchQuery);
$this->db->limit($length,$start);
$cita = $this->db->get()->result();
For some reason the ORDER BY is not set as tbl_notes.notes
Any suggestion on how to fix this?
Thanks in advance
EDIT: i have added more code so there is more visibility of the process
The error occurs, because your column name is not unique, it exists in more than one table.
append the table name of the searched column to your query to make it unique:
for example in this line:
$this->db->order_by('my_table_name.'.$order, $dir);
that would generate something like
ORDER BY `my_table_name.notes` DESC
edit: or in case you have to address columns from several different tables you could change your $valid_columns array:
$valid_columns = array(
0=>'my_table_name1.project_id',
1=>'my_table_name2.client',
2=>'my_table_name2.fullname',
3=>'my_table_name3.notes',
// etc.
);
and maintain the remaining original code.

Same serial number is generating for different requests

I am inserting a serial number in a table that is increment by one always but when multiple request is coming in same time it is inserting same serial number for different requests.I am using mysql database.
I know i am fetching the max serial number too early in the code and if request is come in same time so it will fetching same serial number for both. is it good idea to update serial number after all work done. what if inserting a record for new request and updating the serial number for previous one is in same time.
public function add(){
$session = $this->request->session();
$company_id = $session->read('Admin.company_id');
$emp_id = $session->read('Admin.emp_id');
$user_email_id = $session->read('Admin.email_id');
$employee_name = $session->read('Admin.employee_name');
$conn = ConnectionManager::get('default');
if ($this->request->is('post')) {
try{
$conn->begin();
$department = $this->request->data['department'];
$data = $this->request->data;
if(!array_key_exists('is_requisition_for_contractor', $data)){
$is_requisition_for_contractor = 0;
} else {
$is_requisition_for_contractor = $data['is_requisition_for_contractor'];
}
if(!array_key_exists('is_requisition_for_employee', $data)){
$is_requisition_for_employee = 0;
} else {
$is_requisition_for_employee = $data['is_requisition_for_employee'];
}
if(!array_key_exists('is_boulder_requisition', $data)){
$is_requisition_for_boulder = 0;
} else {
if($data['is_boulder_requisition'] == ''){
$is_requisition_for_boulder = 0;
} else {
$is_requisition_for_boulder = $data['is_boulder_requisition'];
}
}
$is_requisition_for_plant = 0;
if(!array_key_exists('is_plant_requisition', $data)){
$is_requisition_for_plant = 0;
} else {
if($data['is_plant_requisition'] == ''){
$is_requisition_for_plant = 0;
} else {
$is_requisition_for_plant = $data['is_plant_requisition'];
}
}
if(array_key_exists("files",$this->request->data)) {
$files = $this->request->data['files'];
if (count($files)) {
$files_uploading_response = $this->uploadMultipleFiles($files, 'files/requisitions/');
}
}
$last_material_insert_id = '';
if($this->request->data('material_id')[0] == ''){
if($this->request->data('department') == 1){
$type = 1;
} elseif($this->request->data('department') == 3){
$type = 3;
} elseif($this->request->data('department') == 2){
$type = 2;
}
if($this->request->data('department') == 1 || $this->request->data('department') == 3){
$conn->execute("INSERT INTO material (material_name, material_type_id, company_id, status, is_approved_by_admin) VALUES (?,?,?,?,?)",[$this->request->data('material_name'), $type, $company_id, 1,0]);
$last_material_insert_id = $conn->execute("SELECT LAST_INSERT_ID() AS last_id")->fetchAll('assoc');
} elseif($this->request->data('department') == 2) {
//todo for unapproved material
$conn->execute("INSERT INTO material (part_no, material_type_id, company_id, status, is_approved_by_admin,unique_category_id) VALUES (?,?,?,?,?,?)",[$this->request->data('part_no')[0], $type, $company_id, 1,0,$this->request->data('unique_category_id')[0]]);
$last_material_insert_id = $conn->execute("SELECT LAST_INSERT_ID() AS last_id")->fetchAll('assoc');
}
}
// here i am fatching max serial number from table
$requistion_number = $conn->execute("SELECT IF(MAX(requisition_no) IS NULL, 0,MAX(requisition_no)) AS requisition_no FROM requisition WHERE site_id = ?",[$this->request->data('site_id')])->fetchAll('assoc');
$Requisition = TableRegistry::get('requisition');
$requisition = $Requisition->newEntity();
$requisition->registered_on = $this->request->data['date'];
$requisition->department_id = $this->request->data('department');
$requisition->site_id = $this->request->data('site_id');
$requisition->issues_to_id = $this->request->data['prepared_by_id'];
$requisition->prepared_by_id = $this->request->data['prepared_by_id'];
$requisition->approved_by_id = $this->request->data['hod_id'];
$requisition->hod_id = $this->request->data['hod_id'];
$requisition->is_diesel_requisition_for_employee = $is_requisition_for_employee;
$requisition->is_diesel_requisition_for_contractor = $is_requisition_for_contractor;
$requisition->is_requisition_for_boulder = $is_requisition_for_boulder;
$requisition->is_requisition_for_plant = $is_requisition_for_plant;
if(array_key_exists('for_tanker_stock', $this->request->data)) {
$requisition->for_tanker_stock = 1;
}
if($last_material_insert_id != ''){
$requisition->is_material_approved_by_admin = 0;
}
$requisition->status = 1;
$site_id = $this->request->data['site_id'];
$requisition->requisition_no = $requistion_number[0]['requisition_no'] + 1;
$requistionnumber = $requistion_number[0]['requisition_no'] + 1;
$saveRequsition = $Requisition->save($requisition);
$conn->commit();
}
I am expecting the output different serial number for each request.any optimise way to do this. thanks in advance.
Ok, how about the same strategy, setting the $requisition_number after the row has been inserted (see my other answer), but using a single query with the same method you use to determine the new requisition id:
$conn->execute("UPDATE requisition
SET requisition_no = (SELECT IF(MAX(requisition_no) IS NULL, 0,MAX(requisition_no)) AS requisition_no FROM requisition WHERE site_id = ?) + 1",
[$this->request->data('site_id')]);
The idea here is that a single query will be executed in one step, without another, similar query, being able to interfere.
What you currently do is to first get the old requistion number like this:
$requistion_number = $conn->execute("SELECT IF(MAX(requisition_no) IS NULL, 0,MAX(requisition_no)) AS requisition_no
FROM requisition WHERE site_id = ?",[$this->request->data('site_id')])->fetchAll('assoc');
and then increase it before you save and commit.
My suggestion is to not set the $requistion_number at all before you save and commit the requisition row, but to determine the $requistion_number afterwards.
You now wonder how?
Well, you need to count the total number of requisition rows in the table for the site the requisition is for, and add one, like this:
$last_requisition_id = $conn->execute("SELECT LAST_INSERT_ID() AS last_id")->fetchAll('assoc');
$site_id = $this->request->data('site_id');
$requisition_number = $conn->execute("SELECT COUNT(*) AS requisitionsCount
FROM requisition
WHERE <primary_key> <= ? AND
site_id = ?",
[$last_requisition_id, $site_id]) + 1;
$conn->execute("UPDATE requisition
SET requisition_no = ?
WHERE <primary_key> <= ?",
[$requisition_number, $last_requisition_id]);
I know this code is not working. The $requisition_number will probably contain an array with the requisitionsCount as a value, but you can correct that.
Because you're using data that is already present in the database table you don't run the risk that two rows will get the same $requisition_number. The assumption here is that requisitions are never deleted.

CSV that needs to be processed row by row by PHP takes ages (or timeouts) to get into a SQL database

I have a comparison website, on which I'm every night updating the feeds from the stores. These are generally not the largest feeds (ie. max. 15.000 rows), but even a CSV feed with only 1000 rows can take ages because of the (many?) SQL-queries I have to do. This is my procedure:
Every CSV feed comes from a different affiliate network, and so, has a different index and structure. This is why I've programmed a page that first standardize every feed to the right structure (ie. $row['name'] = $col[1] in one feed, but $col[2] in another feed). These 'right' data will be processed by another function CheckProduct();.
In CheckProduct() I'm first checking if a product already exists. If yes, then I'm updating the standard information: current price, stock, url etc. If no, I'm inserting the product into the database.
But that last point takes so much time, that even one extra query can take another few minutes. I don't think it has to take so long, but I keep looking to this code and looking for SQL-query optimization, but I can not seem to figure out how I can keep this procedure, when I'm bulk or combining CSV rows. I already tried to optimize queries (using COUNT() instead of num_rows, only selecting the columns I need, etc.).
I'm not an expert in programming, but I know there must be a different option. I know you can store things in an array and then loop that, or use LOAD DATA INFILE, but I don't know how to programme that in this case (and still have the same kind of strict checks every row). In other words: how can I optimize this code?
This is the function CheckProduct()
function CheckProduct($SiteID, $StoreID, $FeedID, $Name, $URL, $Description, $EANSKU, $Image, $Brand, $Color, $Price, $CategoryPath, $Stock, $Deliverycosts, $Deliverytime, $Length, $Width, $Depth, $Height, $Material)
{
global $db;
if ( !filter_var($URL, FILTER_VALIDATE_URL) === false && !filter_var($Image, FILTER_VALIDATE_URL) === false && !empty($Name) && !empty($URL) && !empty($Price) && !empty($Image) ) {
$sCountProduct = $db->query("SELECT COUNT(*) as total FROM furniture WHERE name_slug='".CreateSlug(trim($db->real_escape_string($Naam)))."' AND feed_id='".$FeedID."' LIMIT 1");
$fCountProduct = $sCountProduct->fetch_assoc();
if($fCountProduct['total'] == '0') {
$iProduct = $db->query("INSERT INTO furniture (site_id,feed_id,store_id,name,name_slug,affiliate_url,description,ean_sku,image_big,brand,brand_slug,color,color_slug,price,category_path,in_stock,visible,shipping_costs,check_today,last_update,deliverytime,length,width,depth,height,material,material_slug,added) VALUES ('1','".$FeedID."','".$StoreID."','".trim($db->real_escape_string($Name))."','".CreateSlug(trim($db->real_escape_string($Name)))."','".trim($AffiliateURL)."','".$db->real_escape_string(trim($Description))."', '".$db->real_escape_string(trim($EANSKU))."','".trim($Afbeelding)."','".$db->real_escape_string(trim($Brand))."','".CreateSlug($db->real_escape_string(trim($Brand)))."','".$db->real_escape_string(trim($Color))."','".CreateSlug($db->real_escape_string(trim($Color)))."','".$db->real_escape_string(trim($Price))."','".$db->real_escape_string(trim(strtolower($CategoryPath)))."','".$Stock."', '3','".$db->real_escape_string(trim($Deliverycosts))."','1','".time()."','".$db->real_escape_string(trim($Deliverytime))."','".$db->real_escape_string(trim($Length))."','".$db->real_escape_string(trim($Width))."','".$db->real_escape_string(trim($Depth))."','".$db->real_escape_string(trim($Height))."','".$db->real_escape_string(trim($Material))."','".CreateSlug($db->real_escape_string(trim($Material)))."','".date('d-m-Y')."')");
$IDProduct = $db->insert_id;
if($iProduct) {
$dOthers = $vm->query("DELETE FROM furniture WHERE name_slug='".CreateSlug(trim($db->real_escape_string($Name)))."' AND id != '".$IDProduct."' AND feed_id='".$FeedID."' AND visible != '1'");
}
}
else {
$sExistProduct = $db->query("SELECT id,site_id,name_slug,feed_id,price_old,visible,price FROM furniture WHERE site_id='1' AND name_slug='".CreateSlug(trim($db->real_escape_string($Name)))."' AND feed_id='".$FeedID."' LIMIT 1");
if(!$sExistProduct) { }
else {
// Check if it is a salesproduct
$fExistProduct = $sExistProduct->fetch_assoc();
$OudePrijs = $fExistProduct['price_old'];
$Zichtbaar = $fExistProduct['visible'];
if($fExistProduct['visible'] == '2'){ $Visible = '1'; }
if($Price < $fExistProduct['price']){ $OldPrice = $fExistProduct['price']; }
$uProduct = $db->query("UPDATE furniture SET affiliate_url='".trim($URL)."', description='".$db->real_escape_string(trim($Description))."', price='".$db->real_escape_string(trim($Price))."', price_old='".$db->real_escape_string(trim($OldPrice))."', in_stock='".$Stock."', shipping_costs='".$db->real_escape_string(trim($Deliverycosts))."', check_today='1', last_update='".time()."', deliverytime='".$Deliverytime."', visible='".$Visible."' WHERE id='".$fExistProduct['id']."' LIMIT 1");
if($uProduct) {
// Updated
}
}
}
}
else
{
// Error in image (not every image send by the feed is a good one)
}
}
This is how I process one of my feeds to match the correct columns:
$SiteID = '1';
$FeedID = '1';
$StoreID = '1';
$Link = 'URL';
if (($handle = fopen($Link, "r")) !== FALSE) {
fgetcsv($handle);
$i = 0;
while (($data = fgetcsv($handle, 6000, ";")) !== FALSE) {
$num = count($data);
for ($c=0; $c < $num; $c++){ $col[$c] = $data[$c]; }
### VARIABLES FROM FEED ###
$Name = $col[1];
$URL = $col[5];
$Description = strip_tags($col[4]);
$EANSKU = $col[0];
$Image = $col[6];
$Brand = $col[8];
$Color = '';
$Price = $col[3];
$CategoryPath = $col[9];
$Stock = $col[10];
$Deliverycosts = $col[14];
$Deliverytime = '';
$Length = '';
$Width = '';
$Height = '';
$Depth = '';
$Material = '';
### STOCK ###
if($Stock > 0) {
$Stock = '1';
}
else {
$Stock = '0';
}
### SEND PRODUCT ###
CheckProduct($SiteID, $StoreID, $FeedID, $Name, $URL, $Description, $EANSKU, $Image, $Brand, $Color, $Price, $CategoryPath, $Stock, $Deliverycosts, $Deliverytime, $Length, $Width, $Depth, $Height, $Material);
$i++;
}
fclose($handle);
}
I'm using PHP 5.6.32 and MySQL 5.0.11.
SELECT COUNT(*) doesn't need a limit...
Just pre-select the data:
SELECT name_slug,feed_id, COUNT(*) as cnt as total FROM furniture GROUP BY name_slug,feed_id");
SELECT name_slug,feed_id, id,site_id,name_slug,feed_id,price_old,visible,price FROM furniture WHERE site_id='1'
and use them as lookup tables.
Then batch your inserts/deletes/updates, and the entire script should take
less than a few sec.
Or do it all in mysql...

Constructing large PHP query

I'm working with WordPress with custom fields and trying to convert a query which was initially written for pjjtextbase (textfile database) to search a csv file for matching properties for rent/sale.
I understand that to query a custom posts in WP with custom fields I would write something like;
$location = preg_replace('/^-|-$|[^-a-zA-Z0-9]/', '', $_GET['location']);
$type = preg_replace('/^-|-$|[^-a-zA-Z0-9]/', '', $_GET['type']);
$buyrent = preg_replace('/^-|-$|[^-a-zA-Z0-9]/', '', $_GET['buyrent']);
$min_val =preg_replace('/[^0-9]/', '', $_GET['min_val']);
$room_no_min = preg_replace('/[^0-9]/', '', $_GET['room_no_min']);
// This replaces characters in the input string if need be for security reasons
$args =
array(
'post_type' => 'properties',
'meta_query' =>
array(
'key' => 'wp_location',
'value' => $location,
'compare' => '=',
)
);
$results = new WP_Query($args);
But when I look at the code the programmer wrote
/***** THESE VALUES NEEDED FOR SELECT BOX *****/
$locations = ptb_listUnique($info, 'Property_Location');
$property_type = ptb_listUnique($info, 'Property_Type');
$property_buy_rent = ptb_listUnique($info, 'Buy_Rent');
//check property
$query = Array();
if(!empty($_GET['location'])) {
$query[] = "'Property_Location' == '".$_GET['location']."'";
}
if(!empty($_GET['type'])) {
$query[] = "'Property_Type' == '".$_GET['type']."'";
}
if(!empty($_GET['buyrent'])) {
$query[] = "'Buy_Rent' == '".$_GET['buyrent']."'";
}
//check price
if(empty($_GET['buyrent']) || $_GET['buyrent']=="Buy"){
if(!empty($_GET["min_val_buy"]) && is_numeric($_GET["min_val_buy"])){
$min_val_buy = $_GET["min_val_buy"];
}
if(!empty($_GET["max_val_buy"]) && is_numeric($_GET["max_val_buy"])){
$max_val_buy = $_GET["max_val_buy"];
}
$min_val_buy = min($_GET["min_val_buy"], $_GET["max_val_buy"]);
$max_val_buy = max($_GET["min_val_buy"], $_GET["max_val_buy"]);
$query[] = "'Price_Rent' >= '".$min_val_buy."'";
$query[] = "'Price_Rent' <= '".$max_val_buy."'";
}else{
if(!empty($_GET["min_val_rent"]) && is_numeric($_GET["min_val_rent"])){
$min_val = $_GET["min_val_rent"];
}
if(!empty($_GET["max_val_rent"]) && is_numeric($_GET["max_val_rent"])){
$max_val = $_GET["max_val_rent"];
}
$min_val_rent = min($_GET["min_val_rent"], $_GET["max_val_rent"]);
$max_val_rent = max($_GET["min_val_rent"], $_GET["max_val_rent"]);
$query[] = "'Price_Rent' >= '".$min_val_rent."'";
$query[] = "'Price_Rent' <= '".$max_val_rent."'";
}
//check bedrooms
if(!empty($_GET["room_no_min"]) && is_numeric($_GET["room_no_min"])){
$room_min_val = $_GET["room_no_min"];
}
if(!empty($_GET["room_no_max"]) && is_numeric($_GET["room_no_max"])){
$room_max_val = $_GET["room_no_max"];
}
$room_min_val = min($_GET["room_no_min"], $_GET["room_no_max"]);
$room_max_val = max($_GET["room_no_min"], $_GET["room_no_max"]);
$query[] = "'No_Bedrooms' >= '".$room_min_val."'";
$query[] = "'No_Bedrooms' <= '".$room_max_val."'";
//Now build the query to search
$query = implode(' AND ', $query);
It dawned on me that he is not creating multiple queries and then using IMPLODE to combine them but rather creating one whole string then using IMPLODE to add the AND to create the actual query.
The custom fields I have in WP are exactly the same as the large code variable except they are preceded with wp_.
So my question is how do I go about converting his code into a WordPress query?

MySQL Search from Multiple User supplied where clause - Fix and Better Algorithm

I want to run search query where i have multiple where clause. and multiple depends upon the user argument.
for example i mean, Search may depend on 1 column, 2 column, 3 column or 6 column in my case, and i don't want to run if-elseif-else statement with all column probability. So, i have just built up below function, but i am stuck with and that comes in between multiple column search case. Below is my code :-
function listPlayer($player="player_guest", $group="group_guest",
$weapon="weapon_guest", $point="point_guest", $power="level_guest",
$status="status_guest") {
$lePlayer = (isset($player) && $player != "player_guest") ?
'player= '.$mysqli->real_escape_string($player).' and' : '';
$leGroup = (isset($group) && $group != "group_guest") ?
'group= '.$mysqli->real_escape_string($group).' and' : '';
$leWeapon = (isset($weapon) && $weapon != "weapon_guest") ?
'weapon= '.$mysqli->real_escape_string($weapon).' and' : '';
$lePoint = (isset($point) && $point != "point_guest") ?
'point= '.$mysqli->real_escape_string($point).' and' : '';
$lePower = (isset($power) && $power != "level_guest") ?
'level= '.$mysqli->real_escape_string($power).' and' : '';
$leStatus = (isset($status) && $status != "status_guest") ?
'status= '.$mysqli->real_escape_string($status).' and' : '';
$query = "Select pid, name from game where {$lePlayer} {$leGroup} {$leWeapon} {$lePoint} {$lePower} {$leStatus} ";
$runQuery = $mysqli->query($query);
}
but problem is and at the end. If i use them, than i have extra and at the end, and if i don't use them that's again an error.
Can some one help me to fix and find better way to do it.
Update: My Update Code that works if some one needs them Thanks to Barmar
function listPlayer($player="player_guest", $group="group_guest",
$weapon="weapon_guest", $point="point_guest", $power="level_guest",
$status="status_guest") {
$lePlayer = (isset($player) && $player != "player_guest") ?
'player= '.$mysqli->real_escape_string($player) : '' ;
$leGroup = (isset($group) && $group != "group_guest") ?
'group= '.$mysqli->real_escape_string($group) : '' ;
$leWeapon = (isset($weapon) && $weapon != "weapon_guest") ?
'weapon= '.$mysqli->real_escape_string($weapon) : '' ;
$lePoint = (isset($point) && $point != "point_guest") ?
'point= '.$mysqli->real_escape_string($point) : '' ;
$lePower = (isset($power) && $power != "level_guest") ?
'level= '.$mysqli->real_escape_string($power) : '' ;
$leStatus = (isset($status) && $status != "status_guest") ?
'status= '.$mysqli->real_escape_string($status) : '' ;
$condition_array = ( $lePlayer , $leGroup , $leWeapon , $lePoint , $lePower , $leStatus)
$condition_stirng = implode(' and ', $condition_array);
$query = "Select pid, name from game where ".$condition_stirng;
$runQuery = $mysqli->query($query);
}
Update:
I got mail from someone at my email which says my code is vulnerable to SQL Injection. Here it is POC http://www.worldofhacker.com/2013/09/interesting-sql-vulnerable-code-even.html
Thanks
Put all the conditions in an array. Then combine them with:
$condition_string = implode(' and ', $condition_array);
The simple solution is to trim the "and" off at the end:
$query = substr($query, 0, strlen($query) - 3);
however a more efficient way would be to put them in a loop, like this:
$wheres = array("player_guest"=>$player, "group_guest"=>$group.....);
$query_where = "";
$i = 0;
foreach($wheres as $where=>$value){
list($condition, $null) = explode("_",$where);
if(isset($value)){
$query_where .= $condition . "='" . $mysqli->real_escape_string($value)."'";
if($i != sizeof($wheres)){
$query_where .= " and ";
}
}
$i++;
}
This is extendable for any number of conditions, and doesnt require the extra string function at the end.
Notice the $defaults is needed to make sure your conditions work. A bit repetitive, but it's all due to your function declaration.
function listPlayer(
$player="player_guest",
$group="group_guest",
$weapon="weapon_guest",
$point="point_guest",
$power="level_guest",
$status="status_guest") {
//I'm just copying whatever is in the default parameters ;)
$defaults = array(
'player' => 'player_guest',
'group' => 'group_guest',
'weapon' => 'weapon_guest',
'point' => 'point_guest',
'power' => 'level_guest',
'status' => 'status_guest'
);
//Set all user parameters into an array, easier to loop through
$data = compact(array_flip($defaults));
//Then we build conditions
$conditions = array();
foreach($data as $k => $v) {
if ($defaults[k] !== $v) {
$v = $mysqli->real_escape_string($v);
$conditions[] = "$k='$v'";
}
}
//And build query
$query = "SELECT pid, name FROM game WHERE ".implode(" AND ", $conditions);
$runQuery = $mysqli->query($query);
}
First of all I recommend you to look at PDO when you work with MySQL in PHP.
Such tasks are always simply solved with array maps.
function listPlayer($player = null, $group = null, $weapon = null, $point = null, $power = null, $status = null) {
$defaults = array(
'player' => 'player_guest',
'group' => 'group_guest',
'weapon' => 'weapon_guest',
'point' => 'point_guest',
'status' => 'status_guest',
);
$values = compact(array_keys($defaults));
$filtered = array_filter(array_diff_assoc($values, $defaults)); //firstly filtering out defaults, then - nulls.
$where = '';
foreach($filtered as $column => $value){
if($where){
$where .= ' AND ';
}
$where .= sprintf("`%s` = '%s'", $column, $mysqli->real_escape_string($value));
}
$query = "SELECT pid, name FROM game WHERE $where";
//executing...
}

Categories