do while loop php with multiple conditions - php

I am posting full code here for make my situation more clear.
<?php
require '../includes/env.php';
require '../includes/db.inc.php';
$total_campaigns = 0;
$total_checked_campaigns = 0;
$checked_campaigns_ids ="0";
$current_campaign_id = 0;
$c_rull = 1;
$c_daily_limit = 0;
/*get all live campaigns count*/
$total_campaigns = get_total_campaigns($conn);
/*check if any campaign available for send data*/
if($total_campaigns>0){
do {
//get one campaign id from all available campaigns.
$c_id = get_campaign($total_campaigns,$total_checked_campaigns,$checked_campaigns_ids,$current_campaign_id,$conn);
/*this while loop is checking that selected campaign have reached daily limit or not,if above campaign id reached limit, it should get another possible campaign id, if there no any campaign id avaialble
get_campaign function will return 0 and we will stop the loop*/
} while(!(($c_id == 0 || $total_checked_campaigns <= $total_campaigns) && is_daily_limit_allow($c_id,$c_daily_limit,$conn)));
echo $c_id;
}
function get_campaign($total_campaigns,$total_checked_campaigns,$checked_campaigns_ids,$current_campaign_id,$conn){
$c_status = 1;//live
$c_lead_status = 0;//not processed
$selectCampaignQuery = "SELECT * FROM tbl_software_campaigns WHERE c_lead_status = ? AND c_status = ? AND c_id > ? AND c_id NOT IN($checked_campaigns_ids) ORDER by c_id ASC LIMIT 1";
$stmt = $conn->prepare($selectCampaignQuery);
$stmt->bind_param("iii", $c_lead_status,$c_status, $current_campaign_id);
$stmt->execute();
$selectCampaignResult = $stmt->get_result();
if ($selectCampaignResult->num_rows==0) {
if($total_checked_campaigns==0){
$update_campaigns_query = "UPDATE tbl_software_campaigns SET c_lead_status = 0 WHERE c_status = 1";
$update_campaign_result = mysqli_query($conn,$update_campaigns_query);
$selectCampaignQuery = "SELECT * FROM tbl_software_campaigns WHERE c_lead_status = ? AND c_status = ? AND c_id > ? AND c_id NOT IN($checked_campaigns_ids) ORDER by c_id ASC LIMIT 1";
$stmt = $conn->prepare($selectCampaignQuery);
$stmt->bind_param("iii", $c_lead_status,$c_status, $current_campaign_id);
$stmt->execute();
$selectCampaignResult = $stmt->get_result();
}
}
if ($selectCampaignResult->num_rows>0) {
global $total_checked_campaigns;
global $c_daily_limit;
global $checked_campaigns_ids;
$row = mysqli_fetch_assoc($selectCampaignResult);
$c_id = $row['c_id'];
$c_daily_limit = $row['c_daily_limit'];
// we are updating total checked campaign count here as well updating comma seperated list of checked campaign id here in below two line
$total_checked_campaigns = $total_checked_campaigns+1;
$checked_campaigns_ids = $checked_campaigns_ids.",".$c_id;
//return campaign id for process the data
return $c_id;
}else{
//return 0 because there no any campaign available to process data
return 0;
}
}
function get_total_campaigns($conn){
$stmt = $conn->prepare("SELECT COUNT(c_id) AS total_campaigns FROM tbl_software_campaigns WHERE c_status = 1");
$stmt->execute();
$total_result = $stmt->get_result();
$row = mysqli_fetch_assoc($total_result);
$stmt->close();
return $row['total_campaigns'];
}
function is_duplicate($EMAIL,$conn){
$query = "SELECT lead_id FROM tbl_software_leads WHERE lead_email = ?";
$stmt = $conn->prepare($query);
$stmt->bind_param("s", $EMAIL);
$stmt->execute();
$duplicate_result = $stmt->get_result();
$stmt->close();
if ($duplicate_result->num_rows>0){
return true;
}else{
return false;
}
}
function is_daily_limit_allow($CAMPAIGN,$LIMIT,$conn){
if($LIMIT>0){
$limit_query = "SELECT count(*) as today_total FROM tbl_software_leads WHERE DATE(lead_time)=CURDATE() AND lead_camp_id =? AND lead_status = 1";
$stmt = $conn->prepare($limit_query);
$stmt->bind_param('i',$CAMPAIGN);
$stmt->execute();
$limitrow = $stmt->get_result()->fetch_assoc();
$todaysrecord = $limitrow['today_total'];
if($todaysrecord<$LIMIT){
return true;
}else{
return false;
}
}else{
return true;
}
}
?>
Now Let me explain my goal.
What I am looking to do is
on start its checking how many campaigns available there!
if campaign available more than 0, I am getting one campaign id and marking that campaign as checked campaign using get_campaign function
get_campaign function giving me campaign id and if there no any campaign available for process, its give me 0 as id.
if there 0 as id, I do not want do anything since it means there no any campaign available for handle the data
if get_campaign give me any campaign id, I need to check that its reached daily limit or not with is_daily_limit_allow function, if its reached that limit, I need to get new id using get_campaign function and check its daily limit.
I am trying to achieve above thing with while loop but its not working properly and running for infinity time.
Basically when
if campaign id is 0, I want stop the loop
if total checked campaigns equal to total campaigns, I want stop the loop because it means we have checked all campaigns and none are available for process the data
if current campaign id allow to process data and have not daily limit, I want stop the loop.
I should also clear that when
$c_daily_limit = 0;
means there no any daily limit in that campaign.
I hope its clear everything now and will help to expert here on stackoverflow.
Let me know if anyone can help me for solve the puzzle.
Thanks!

You said
if campaign id is 0, I want stop the loop
if total checked campaigns equal to total campaigns, I want stop the loop because it means we have checked all campaigns and none are
available for process the data
if current campaign id allow to process data and have not daily limit, I want stop the loop.
So, it makes straightforward conditions as below,
while($c_id != 0 && $total_checked_campaigns < $total_campaigns && is_daily_limit_allow($c_id,$c_daily_limit,$conn));

Try below snippet once
do {
echo $c_id;
echo "<br>";
$c_id = get_campaign($total_campaigns);
} while (($c_id == 0 || $total_checked_campaigns <= $total_campaigns) && is_daily_limit_allow($c_id));
here I changed condiotions as per your trying to get
(($c_id == 0 || $total_checked_campaigns <= $total_campaigns) && is_daily_limit_allow($c_id))

as i understand can you try this code
do {
echo $c_id;
echo "<br>";
$c_id = get_campaign($total_campaigns);
} while (($c_id != 0 && $total_checked_campaigns <= $total_campaigns) || !is_daily_limit_allow($c_id));
or
while(!(($c_id == 0 || $total_checked_campaigns <= $total_campaigns) && is_daily_limit_allow($c_id)))

Related

Why is store_result() not returning num_rows equivalent to mysqli Regular Statement?

I've been combing through previous questions and trying many solutions but cannot figure this out. I'm trying to convert this query to a Prepared Statement:
$query = mysqli_query($this->con, "SELECT * FROM notifications WHERE user_to='$userLoggedIn' ORDER BY id DESC");
Here is what I have:
$query = $this->con->stmt_init();
$query->prepare('SELECT * FROM notifications WHERE user_to=? ORDER BY id DESC');
$query->bind_param('s', $userLoggedIn);
$query->execute();
$query->store_result();
$qty = $query->num_rows;
$query_result = $query->get_result();
Below this code I have variables being used like this:
if($qty == 0) {
echo "<li class='no-more-posts' style='height: 0px; text-transform: uppercase;'>- You have no notifications! -</li>";
return;
}
$num_iterations = 0; //Number of messages checked
$count = 1; //Number of messages posted
while($row = $query_result->fetch_assoc()) {
if($num_iterations++ < $start)
continue;
if($count > $limit)
break;
else
$count++;
$user_from = $row['user_from'];
etc.etc.
What I am getting is blank result in my dropdown. If I change the while statement back to the original while($row = mysqli_fetch_array($query)) { (which I know is wrong and from old statement) my result is always returning the li No More Posts to Show. This tells me that $qty = $query->num_rows; is returning 0. Based on documentation my understanding is that once I buffered the result set with store_result() I could call $qty = $query->num_rows; right after. What am I missing here?
I'm certain this isn't the most efficient way to do things, but it's all I have on it; decided to break the statement up.
First I did a statement for the count:
$query_count = $this->con->stmt_init();
$query_count->prepare('SELECT COUNT(*) FROM notifications WHERE user_to=?');
$query_count->bind_param('s', $userLoggedIn);
$query_count->execute();
$query_count_result = $query_count->get_result();
$rows_count = $query_count_result->fetch_array();
$qty = array_shift($rows_count);
Then I did a statement for the data:
$query = $this->con->stmt_init();
$query->prepare('SELECT * FROM notifications WHERE user_to=? ORDER BY id DESC');
$query->bind_param('s', $userLoggedIn);
$query->execute();
$query_result = $query->get_result();
It solved my problem & everything works as expected. I know there is a better way to do this, so if someone has that suggestion great. In the meantime this will have to do.

Is it possible to loop through the mysql table rows and check columns?

I have a "matrix" table with the following columns filled in.
matrix_id, user_id, position_1, position_2, position_3
1 1 1982 2251 5841
2 2 6204 0 0
3 3 0 0 0
4 4 0 0 0
I basically want to do the following.
Find a row with the lowest user_id and that has an empty position.
In the example above, that would be user_id 2 and position_2.
I update the row with a query.
I then move on to the next next empty position. Since user_id 2 still has an empty position_3, I update the row again with a query.
Since that row is complete, I move on to the next highest user_Id that has empty positions. In this case, it's user_id 3 and then user_id 4 the one after that.
I know I can do all of the above if I know what the user_id is. But assume in this case, I have no clue what the user_ids are. How would the queries look then?
Here is what I have so far.
$find_user = $db->prepare("SELECT * FROM matrix WHERE user_id > :user_id");
$find_user->bindValue(':user_id', 0);
$find_user->execute();
$result_user = $find_user->fetchAll(PDO::FETCH_ASSOC);
if(count($result_user) > 0) {
foreach($result_user as $row) {
$matrix_id = $row['matrix_id'];
$user_id = $row['user_id'];
$position_1 = $row['position_1'];
$position_2 = $row['position_2'];
$position_3 = $row['position_3'];
}
} else {
$errors[] = 'User Id not found in Matrix.';
}
$update_user = $db->prepare("UPDATE matrix SET position_2 = :position_2 WHERE user_id = :user_id");
$update_user->bindValue(':position_2', 1564;
$update_user->bindParam(':user_id', $user_id);
if($update_user->execute()) {}
This should go through all your users from smallest user_id to largest.
For each user it will check the relevant columns in order and apply a new value to the empty ones.
$new_val = 1999;
$result = $db->query("SELECT * FROM matrix ORDER BY user_id");
$users = $result->fetchAll(PDO::FETCH_ASSOC);
if(count($users) > 0) {
// prepare all the possible queries
// make use of prepare once execute many times
$stmt1 = $db->prepare("UPDATE `matrix` SET `position_1` = :pos WHERE `user_id` = :id");
$stmt2 = $db->prepare("UPDATE `matrix` SET `position_2` = :pos WHERE `user_id` = :id");
$stmt3 = $db->prepare("UPDATE `matrix` SET `position_3` = :pos WHERE `user_id` = :id");
foreach($users as $user) {
if ( $user['$position_1'] == 0 ) {
$stmt1->execute( array(':pos'=>++$new_val,':id'=>$user['user_id']) );
}
if ( $user['$position_2'] == 0 ) {
$stmt1->execute( array(':pos'=>++$new_val,':id'=>$user['user_id']) );
}
if ( $user['$position_3'] == 0 ) {
$stmt1->execute( array(':pos'=>++$new_val,':id'=>$user['user_id']) );
}
}
} else {
$errors[] = 'User Id not found in Matrix.';
}
You could reduce the rows to process by changing the query a bit to only find users with columns to fix
$result = $db->query("SELECT *
FROM matrix
WHERE position_1 = 0
OR position_2 = 0
OR position_3 = 0
ORDER BY user_id");
important thing here, is that you are working with the row, not columns
so check all the prerequisites and update the row.
$find_user = $db->prepare("SELECT * FROM matrix order by user_id asc");
$find_user->execute();
$result_user = $find_user->fetchAll(PDO::FETCH_ASSOC);
foreach($result_user as $row) {
$matrix_id = $row['matrix_id'];
$user_id = $row['user_id'];
$position_1 = $row['position_1'];
$position_2 = $row['position_2'];
$position_3 = $row['position_3'];
}
$str = ''
if (!$position_2){
$str = "position_2 = :position_2"
} else if (!$position_2 && !$position_3){
$str = "position_2 = :position_2 and position_3 = :position_3"
}
$update_user = $db->prepare("UPDATE matrix SET " . $str . " WHERE user_id = :user_id");
$update_user->bindValue(':position_2', 1564);
$update_user->bindValue(':position_3', 1564);
$update_user->bindParam(':user_id', $user_id);
if($update_user->execute()) {}
Also, get all the rows in the matrix table ordered by used_id and process every row, depending on your condition.

Unable to get COUNT(*) result from structured SQL statement

I've been working on a SQL statement that checks the database to see if feedback has been left for a specific qr_id from a specific uuid within 24 hours. The original code works as intended, but obviously to be more secure I wanted to change the code to a structed SQL statement instead.
$uuid = "DB8962A3-BC7A-481F-9D7E-C1FC7F74E50E";
$qrid = "2147483647";
$query = sprintf("SELECT COUNT(*) FROM `feedback` WHERE uuid = '%s' AND qr_id = '%s' AND created_on > UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 DAY))", mysql_real_escape_string($uuid), $qrid);
$result = mysql_query($query);
$row = mysql_fetch_assoc($result);
$size = $row['COUNT(*)'];
if ($size > 0){
echo 'Unable to leave feedback as user has left feedback for this employee within 24 hours.';
}else{
echo 'User has not left feedback for this employee within 24 hours, continue.';
}
The above works perfectly fine, if the count is above 0 then it stops the user posting. Here's my attempt at converting it to a structured SQL statement:
$stmt = $this->conn->prepare("SELECT COUNT(*) FROM `feedback` WHERE uuid = ? AND qr_id = ? AND created_on > UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 DAY))");
$stmt->bind_param('si', $uuid, $qrID);
$result = $stmt->execute();
$size = $result['COUNT(*)'];
$stmt->close();
if ($size = 0){
// do post, return true
return true;
}else{
return false;
// do not post, return false
}
I have tried printing the result value and it's always 1, and trying to echo the $size variable returns nothing.
You need to fetch the result, try this:
$stmt->bind_param('si', $uuid, $qrID);
$stmt->execute();
//here you bind result to variable $size
$stmt->bind_result($size);
$stmt->fetch()
$stmt->close();
if ($size == 0){
// do post, return true
return true;
}else{
return false;
// do not post, return false
}

Select Query in Group of 10

I followed one link here, and modified my code accordingly. What I am trying to do achieve is for example a table name media_ids contains 45 rows(which is dyanamic), I want to divide the no of rows in a group of 10 rows minimum (in my case four groups of 10 rows and 1 group of 5) and execute code of each group per hour.
For example from select record from id 1 to 10 then second hour from 11 to 20 and so on unless fetches the last record and start again from id 1.
I added a tracker, which check whats the current limit and proceed.But its giving me the required result what I am trying to achieve.
<?php
require('inc/dbConnect.php');
$lastPointerq = "select tracker from media_tracker";
$lastPointerResult = mysqli_query($con, $lastPointerq);
$lastPointerRes = mysqli_fetch_row($lastPointerResult);
$lastPointer = $lastPointerRes[0];
$lastPointer10=$lastPointer+10;
$currentMediaQuery = "select * from media_ids where id > ".$lastPointer." limit ".$lastPointer.",".$lastPointer10."";
$mediaQuery = mysqli_query($con, $currentMediaQuery);
if (mysqli_num_rows($mediaQuery) > 0) {
while ($row = mysqli_fetch_assoc($mediaQuery)) {
// do stuff…
echo $id=$row['id']."<br>";
}
}
else
{echo "0";}
if ($lastPointer + 10 > 40) {
$lastPointer = 1;
} else {
$lastPointer += 10;
}
mysqli_query($con, "update media_tracker set tracker = $lastPointer");
?>
I am assuming you are calling this script every hour via ajax/Js...
In your code if you delete some data from another script you may find your first row id i.e 100 !
require('inc/dbConnect.php');
$limit = 10 ;
$lastPointerq = "select tracker from media_tracker";
$lastPointerResult = mysqli_query($con, $lastPointerq);
$lastPointerRes = mysqli_fetch_row($lastPointerResult);
$lastPointer = $lastPointerRes[0];
$lastPointerRes = mysqli_fetch_assoc($lastPointerResult);
$lastPointer = empty($lastPointerRes['tracker']) ? 0 : $lastPointerRes['tracker'] ;
$lastPointer10=$lastPointer* $limit;
$currentMediaQuery = "select * from media_ids limit ".$limit." OFFSET ".$lastPointer10."";
$mediaQuery = mysqli_query($con, $currentMediaQuery);
if (mysqli_num_rows($mediaQuery) > 0) {
while ($row = mysqli_fetch_assoc($mediaQuery)) {
// do stuff…
echo $id=$row['id']."<br>";
}
}
else
{echo "0";}
//do a total row count query here and set as value of $total rather than 40
$total =40 ;
$flag = ceil($total/$limit);
if ($lastPointer == $flag) {
$lastPointer = 0;
} else {
$lastPointer ++;
}
mysqli_query($con, "update media_tracker set tracker = $lastPointer");

How can I optimize this function? I need to loop though users, and then loop through user submitted data, and update values, it's taking > 1 minute

How can I optimize this function? I need to loop though users, and then loop through user submitted data, and update values, it's taking > 1 minute for 264 users with around 80 records per user.
public function calculateUserPoints(){
set_time_limit(0);
/* Select users */
$sql = "SELECT user_id FROM users";
$query = $this->db->prepare($sql);
$query->execute();
$users = $query->fetchAll(PDO::FETCH_ASSOC);
/* User guesses Query */
$ug_sql = "SELECT
guesses.guess_id AS r_guess_id, guesses.user_id, guesses.game_id, guesses.team_1_score AS guess_team_1, guesses.team_2_score AS guess_team_2, guesses.joker,
games.game_id, games.game_team_1, games.game_team_2, games.real_score_team_1, games.real_score_team_2,
users.user_id AS usr_id
FROM games
JOIN users
ON users.user_id = :user_id AND games.real_score_team_1 IS NOT NULL AND games.real_score_team_2 IS NOT NULL
LEFT JOIN guesses
ON guesses.user_id = users.user_id
AND guesses.game_id = games.game_id
";
$ug_query = $this->db->prepare($ug_sql);
foreach($users as $u){ /* Loop users */
/* Get guesses per user basis */
/*echo 'User '.$u['user_id'].'<br/>';*/
$ug_query->bindParam(':user_id', $u['user_id']);
$ug_query->execute();
$usr_guesses = $ug_query->fetchAll(PDO::FETCH_ASSOC);
$u_points = 0;
$sql = "UPDATE users SET points = :u_points WHERE user_id = :usr_id";
$query = $this->db->prepare($sql);
$sql2 = "UPDATE guesses SET guess_points = :guess_points WHERE guesses.guess_id = :guess_id";
$query2 = $this->db->prepare($sql2);
foreach($usr_guesses AS $ug){
$err = false;
$g_points = 0;
if(isset($ug['guess_team_1']) && isset($ug['guess_team_1'])){
$g_points = $this->calcPoints($ug['guess_team_1'], $ug['guess_team_2'], $ug['real_score_team_1'], $ug['real_score_team_2'], $ug['joker']);
} else {
$u_points -= 1;
}
$u_points += $g_points;
/* echo $ug['guess_team_1'].' - '.$ug['guess_team_2'].' :: '.' '.$ug['real_score_team_1'].' - '.$ug['real_score_team_2'].' jk: '.$ug['joker'].' / pt: '.$g_points.':: T: '.$u_points.'<br/>';*/
$query->bindParam(':u_points', $u_points);
$query->bindParam(':usr_id', $u['user_id']);
$query2->bindParam(':guess_points', $g_points);
$query2->bindParam(':guess_id', $ug['r_guess_id']);
if($query->execute() && $query2->execute()){
$err = false;
} else {
$err = true;
}
}
}
if($err == true){
return false;
} else {
return true;
}
}
guess_id and user_id are indexes on all columns.
I'm not looking for a code answer, I'd prefer merely a push in the right direction.
Thanks.
$sql = "SELECT user_id FROM users"; can be joined with $ug_sql query into one query.
If you use InnoDB tables, you can do the updates in transaction, it will speed it up.
And think about removing some indexes, they slow down inserts, updates, and deletes.

Categories