PHP Recursion -- Increment query variables - php

I have a database where each row contains a unique userid number, and a referralid number that links them to the person that referred them to the site. I am trying to create a recursive function that will search the database as long as it continues to find users, and perform several calculations as it goes. Below is what I have so far - I am getting stuck on trying to create incrementing query variables - PLEASE HELP!
function findrepsloop($refidnum, $num){
echo "FINDREPSLOOP STARTED<br><br>";
if(strlen($refidnum) > 0){
echo "FIRST STRLEN IF LOOP PASSED: $refidnum<br><br>";
$totalreps++;
$query{$num} = "SELECT * FROM user WHERE (refidnum = '$refidnum' && active = 'YES') ";
$result{$num} = mysql_query($query{$num});
$line{$num} = mysql_fetch_array($result{$num}, MYSQL_NUM);
$total{$num} = mysql_num_rows($result{$num});
echo "QUERY $num found $total{$num} rows in the database. LINE 0: '$line{$num}[0]<br><br>";
$totaltemp = 0;
if($total{$num} > 2){ $totaltemp = $total{$num} / 3; $totaltemp = floor($totaltemp); }else{}
$numberofthrees = $numberofthrees + $totaltemp;
while(strlen($line{$num}[0]) > 0){
$refidnum = $line{$num}[0];
$num++;
findrepsloop($refidnum, $num);
$line{$num} = mysql_fetch_array($result{$num}, MYSQL_NUM);
}
}else{
}
}

Related

How to save query in multidimesional array?

I have this script executing as a cron job everyday to update days remaining to pay invoices. I first query every row of my table and attempt to store the data in a multidimensional array but this seems to be storing everything I query in the first element of my array.
Here's my script:
<?php
include '../inc/dbinfo.inc';
ini_set("log_errors", 1);
ini_set("error_log", "/tmp/php-error.log");
error_log( "################################################# UpdateVendorInvoiceDays.php #################################################" );
$three = 3;
$fetchAllInvoices = "SELECT VENDORINVOICEID, VdrInvoiceReceived, PaymentDue, COUNT(*), DATEDIFF(PaymentDue, NOW()) FROM tblVendorInvoices WHERE VdrInvoiceStatusID != ?";
$getInvoices = $conn->prepare($fetchAllInvoices);
$getInvoices->bind_param("i", $three);
$getInvoices->execute();
$result = $getInvoices->get_result();
$rows = array();
$j = 0;
while($row = $result->fetch_assoc())
{
$rows[$j][] = $row;
$j++;
}
echo json_encode($rows[0][0]); //Only outputs one row
//UPDATE DAYS REMAINING IN EACH ENTRY THAT ISNT PAID
$updateDaysRemaining = "UPDATE tblVendorInvoices SET DaysRemaining = ? WHERE VENDORINVOICEID = ? AND VdrInvoiceStatusID ! = ?";
$setDays = $conn->prepare($updateDaysRemaining);
$k = 0; //incrementor
$numberOfEntries = $rows['COUNT(*)'];
for($k;$k<$numberOfEntries;$k++){
$setDays->bind_param("iii", $rows[$k]["DATEDIFF(PaymentDue, NOW())"],
$rows[$k]['VENDORINVOICEID'], $three);
if($setDays->execute()){
error_log('Cron success');
}else{
error_log('Cron fail');
}
}
?>
Currently the output from my first query is:
[[{"VENDORINVOICEID":88,"VdrInvoiceReceived":"2018-08-21","PaymentDue":"2018-07-27","COUNT(*)":2,"DATEDIFF(PaymentDue, NOW())":-25}]]
and my error log only gives me a notice for $rows['COUNT(*)'] being undefined (which makes sense)
I've looked at other answers here but they don't seem to have the same structure as I do.
EDIT: I also have 2 rows in my database but this only puts out one. I forgot to mention this.
There are a couple of simplifications to get all of the rows. Instead of...
while($row = $result->fetch_assoc())
{
$rows[$j][] = $row;
$j++;
}
echo json_encode($rows[0][0]);
You can just return all rows using fetch_all()...
$rows = $result->fetch_all (MYSQLI_ASSOC);
echo json_encode($rows);
Then encode the whole array and not just the one element - which is what $rows[0][0] was showing you.
As for you other problem - change in your select statement to
COUNT(*) as rowCount
and then you can use this alias for the field reference...
$rows['COUNT(*)']
becomes
$rows['rowCount']

PHP Number Ticket System?

So, I'm trying to make a ticket system. So a users will be assigned 1000 tickets each, I will then generate a number from 1 to 5000, I then need it to select the user.
The way I have done it was made an array then looped 5000 times and assigned each user a ticket, however this doesn't work with really big numbers like 5,000,000. So I'm trying to think of the best way to do this and I'm unsure how.
Any advice?
$users = array();
$ticketNum = 0;
$result = $MySQL->query("SELECT * FROM `users` ");
while($row = $result->fetch_assoc()){
$i = 0;
while($i < $row['points']){
$i++;
$ticketNum++;
$ar = array("ticketNum" => $ticketNum, "username" => $row['username']);
array_push($users, $ar);
}
}
$winningTicket = 2500;
foreach($players as $ar){
if($winningTicket == $ar['ticketNum']){
//winner
}
}
I'll need more code to suggest a perfect solution, and also know why you want to assign 1000 tickets to a person?
But you could assign a from-to key instead of looping ALL of the numbers through, like
$users[$userNumber]["from"] = 1;
$users[$userNumber]["to"] = 6;
$findNumber = rand(1,6);
$foundUser = false;
foreach($users as $userNumber => $user) {
if ($user["from"] <= $findNumber && $user["to"] >= $findNumber) {
$foundUser = $user;
break;
}
}
if ($foundUser) {
print "Hooray, someone just got a ticket.";
}
but it does sound like a job you would solve in a different manner, maybe through your database.
Edit: I wrote the above before you added your code example, In your case I would probably do the following.
$result = $MySQL->query("SELECT username FROM users ORDER BY RAND() LIMIT 1");
$winningUser = $result->fetch_assoc();
print "We got a winner: ".$winningUser["username"];

adding further conditions to mysql loop

<?php
$query = $_GET['query'];
// gets value sent over search form
$min_length = 6;
// you can set minimum length of the query if you want
if(strlen($query) >= $min_length){ // if query length is more or equal minimum length then
$query = htmlspecialchars($query);
// changes characters used in html to their equivalents, for example: < to >
$query = mysql_real_escape_string($query);
// makes sure nobody uses SQL injection
$raw_results = mysql_query("SELECT * FROM cwnational WHERE (`postcode` = '$query') OR (`structure` LIKE '%".$query."%')") or die(mysql_error());
if(mysql_num_rows($raw_results) > 0){ // if one or more rows are returned do following
while($results = mysql_fetch_array($raw_results)){
echo "<p><h3>".$results['postcode']."</h3>".$results['structure']."</p>";
}
while($results = mysql_fetch_array($raw_results)){
if($results['structure'] = "National") {
echo "print national_table";
} else {
echo "print local_table";
}
}
else{ // if there is no matching rows do following
echo "No results";
}
}
else{ // if query length is less than minimum
echo "Minimum length is ".$min_length;
}
?>
</body>
I'm totally stumped now..
When I successfully match a $query, I want to use the 2nd part of the array which should be a column called structure and use that as a switch to either print table_local or table_national from the db.
re-wrote it after getting to grips with the correct approach,
if (empty($searchTerm)) {
echo "<h1>Empty search term</h1>";
$sqlQuery = false;
} elseif (strlen($searchTerm) < $minQueryLength) {
echo "<h1>Search term must be at least ".$minQueryLength." characters long.";
$sqlQuery = false;
} else {
if (strlen($firstPart) + strlen($secondPart) == 7) {
$sqlQuery = $mysqli->query("SELECT `postcode`, `structure` FROM `cwnational` WHERE `postcode` LIKE '".$firstPart." ".$secondPart."'");
} else {
$sqlQuery = $mysqli->query("SELECT `postcode`, `structure` FROM `cwnational` WHERE REPLACE(`postcode`, ' ', '') LIKE '".$searchTerm."%'");
}
}
if (is_object($sqlQuery) && $sqlQuery->num_rows >= 1) {
$resultArr = array();
while($row = $sqlQuery->fetch_assoc()) {
$resultArr[$row['postcode']] = array();
$priceQuery = $mysqli->query("SELECT `base_rate`, `commit_mbps` FROM `pricing` WHERE `structure` = '".$row['structure']."'");
if ($priceQuery->num_rows >= 1) {
while ($price = $priceQuery->fetch_assoc()) {
$resultArr[$row['postcode']][$price['commit_mbps']] = ((float)$price['base_rate'] + $transit[$price['commit_mbps']] ) + ( ( $transit[$price['commit_mbps']] + (float)$price['base_rate'] ) * ((float)$apiUser['margin']/100) ) ;
}
}
}
You're reading the result set twice. This will work for the first loop, but won't execute the second because you've already reached the end. If you need to read the results twice, use this:
mysql_data_seek ($raw_results , 0 )
immediately before the second loop to set the pointer to the beginning again.
Of course, you should be using mysqli...
what's going wrong now? I see you need to add an equals sign here:
if($results['structure'] == "National") {
note: double equals for php conditional
It also looks like you have an "else" coming out of a "while", that won't work. And you did this "while" loop twice, I'd combine them into a single "While":
while($results = mysql_fetch_array($raw_results)){

php sql find and insert in empty slot

I have a game script thing set up, and when it creates a new character I want it to find an empty address for that players house.
The two relevant table fields it inserts are 'city' and 'number'. The 'city' is a random number out of 10, and the 'number' can be 1-250.
What it needs to do though is make sure there's not already an entry with the 2 random numbers it finds in the 'HOUSES' table, and if there is, then change the numbers. Repeat until it finds an 'address' not in use, then insert it.
I have a method set up to do this, but I know it's shoddy- there's probably some more logical and easier way. Any ideas?
UPDATE
Here's my current code:
$found = 0;
while ($found == 0) {
$num = (rand()%250)+1; $city = (rand()%10)+1;
$sql_result2 = mysql_query("SELECT * FROM houses WHERE city='$city' AND number='$num'", $db);
if (mysql_num_rows($sql_result2) == 0) { $found = 1; }
}
You can either do this in PHP as you do or by using a MySQL trigger.
If you stick to the PHP way, then instead of generating a number every time, do something like this
$found = 0;
$cityarr = array();
$numberarr = array();
//create the cityarr
for($i=1; $i<=10;$i++)
$cityarr[] = i;
//create the numberarr
for($i=1; $i<=250;$i++)
$numberarr[] = i;
//shuffle the arrays
shuffle($cityarr);
shuffle($numberarr);
//iterate until you find n unused one
foreach($cityarr as $city) {
foreach($numberarr as $num) {
$sql_result2 = mysql_query("SELECT * FROM houses
WHERE city='$city' AND number='$num'", $db);
if (mysql_num_rows($sql_result2) == 0) {
$found = 1;
break;
}
}
if($found) break;
}
this way you don't check the same value more than once, and you still check randomly.
But you should really consider fetching all your records before the loops, so you only have one query. That would also increase the performance a lot.
like
$taken = array();
for($i=1; $i<=10;$i++)
$taken[i] = array();
$records = mysql_query("SELECT * FROM houses", $db);
while($rec = mysql_fetch_assoc($records)) {
$taken[$rec['city']][] = $rec['number'];
}
for($i=1; $i<=10;$i++)
$cityarr[] = i;
for($i=1; $i<=250;$i++)
$numberarr[] = i;
foreach($cityarr as $city) {
foreach($numberarr as $num) {
if(in_array($num, $taken[]) {
$cityNotTaken = $city;
$numberNotTaken = $number;
$found = 1;
break;
}
}
if($found) break;
}
echo 'City ' . $cityNotTaken . ' number ' . $numberNotTaken . ' is not taken!';
I would go with this method :-)
Doing it the way you say can cause problems when there is only a couple (or even 1 left). It could take ages for the script to find an empty house.
What I recommend doing is insert all 2500 records in the database (combo 1-10 with 1-250) and mark with it if it's empty or not (or create a combo table with user <> house) and match it on that.
With MySQL you can select a random entry from the database witch is empty within no-time!
Because it's only 2500 records, you can do ORDER BY RAND() LIMIT 1 to get a random row. I don't recommend this when you have much more records.

Pagenav. By clicking next get next lets say "20" records (php/mysql)

I've already created a query to mysql that will give 20 results from mysql table etc. "cat"
heres the calling:
if(isset($_GET['cat']))
{
$query = "SELECT game_title,game_desc,....
FROM games WHERE cat_id='".validate_input($_GET['cat'])."' LIMIT 20";
}
...
by this I manage to get the results I wanted. What I am asking here is how can I create a "button" that will load the next "20" records from table "cat" (something like Buttons).
<?
$cn=mysql_connect("localhost","root","root") or die(mysql_error());
mysql_select_db("db56") or die(mysql_error());
$sql="select count(*) from emp";
$result=mysql_query($sql);
$r=mysql_fetch_row($result);
$record=$r[0];
$pagesize=20;
$totalpages=$record/$pagesize;
$currpage=$_GET["pg"];
if(!isset($currpage))
$start=0;
else {
$currpage--;
$start= $currpage * $pagesize;
}
$end=$start+$pagesize;
$sql="select * from emp limit $start,$pagesize";
$result=mysql_query($sql);
if($result){
print "<table border='1'>";
print "<tr><th>No</th><th>Name</th><th>Date</th></tr>";
while($r=mysql_fetch_row($result))
{
print "<tr><td>$r[0]</td><td>$r[1]</td><td>$r[2]</td></tr>";
}
print "</table>";
}
for($i=1;$i<=$totalpages;$i++){
print "<a href='listemp.php?pg=$i'> $i </a>";
}
?>
If you keep track of what page you're on, in the URL or a hidden field or session variable, you can use that to work out the limit. For example, page 2 should show limit 20 from row 20 (20 times the page offset).
You can pass two SQL parameters to LIMIT (put a comma between them) If you do, the first tells SQL how many records to skip (ie the offset of the first record) and the 2nd parameter is the one you're already using (how many records to return).
So just put a variable in your "next" link that says what page to display. You can pass the offset in this link, but it's pretty common to pass the "page number" instead, and multiply by the number of records per page before sticking it in the sql.
next page
With a bit more work, you can make a "previous page" link, and make the correct links non-clickable when you're at the first/last page.
Pass along a parameter that tells the script that you want another chunk of the results and not just the first batch.
So for the link it could be like this:
example.com/results.php?cat=1&page=2
Where page= will tell the script what page you want to return.
Then you want to turn that LIMIT number you have so that you can work out some simple maths
$results_cnt = 20; //--rows you want per page of results
Now in your script you'll check to see if the page variable has been set. If not, default the start row to return from the first. But as you want to return different pages/sets of results, a little math is needed in order to start at the proper row.
if(isset($_GET["page"]) //--see if the variable is even there
{
$page_num = (int)$_GET["page"]; //--forcing it to always be an integer
$start_row = $results_cnt * ($page_num - 1);
/* --
what happens:
($results_cnt currently at 20)
on page one (page=1), start at row 0
math: 20 * (1 - 1) = 0
on page two (page=2), start at row 20
math: 20 * (2 - 1) = 20
on page three (page=3), start at row 40
math: 20 * (3 - 1) = 40
etc.
*/
}
else
$start_row = 0;
Now, having set the correct starting row, adjust the SQL query to use the variables like so:
if(isset($_GET['cat']))
{
$query = "SELECT game_title,game_desc,....
FROM games
WHERE cat_id='".validate_input($_GET['cat'])."'
LIMIT $start_row, $results_cnt";
}
OK I got it fixed I guess...
in index.php:
<?php
$games = array();
$count = 1;
$total = 0;
if(isset($_GET['cat']))
{
$query = "SELECT game_title,game_desc,.... FROM games WHERE cat_id='".validate_input($_GET['cat'])."' LIMIT 20";
$total = mysql_num_rows(mysql_query("SELECT 1 FROM games WHERE cat_id='".validate_input($_GET['cat'])."'"));
}
$query_result = #mysql_query ($query) OR error(mysql_error(), __LINE__, __FILE__, 0, '', '');
while ($info = #mysql_fetch_array($query_result))
{
/* -- here goes the infos.. */
$games[$info['game_title']]['game_title'] = $info['game_title'];
etc..
if(isset($_GET['cat']))
{
/* -- for template engine */
$page->SetLoop ('PAGES', pagenav($total,$_GET['page'],20,$config['site_url'].'?cat='.$_GET['cat'],1,$lang));
}
--end php
and in funct.php
--start php
function pagenav($total,$page,$perpage,$url,$posts=0)
{
$page_arr = array();
$arr_count = 0;
if($posts)
{
$symb='&';
}
else
{
$symb='?';
}
$total_pages = ceil($total/$perpage);
$llimit = 1;
$rlimit = $total_pages;
$window = 5;
$html = '';
if ($page<1 || !$page)
{
$page=1;
}
if(($page - floor($window/5)) <= 0)
{
$llimit = 1;
if($window > $total_pages)
{
$rlimit = $total_pages;
}
else
{
$rlimit = $window;
}
}
else
{
if(($page + floor($window/2)) > $total_pages)
{
if ($total_pages - $window < 0)
{
$llimit = 1;
}
else
{
$llimit = $total_pages - $window + 1;
}
$rlimit = $total_pages;
}
else
{
$llimit = $page - floor($window/2);
$rlimit = $page + floor($window/2);
}
}
if ($page>1)
{
$page_arr[$arr_count]['title'] = 'Prev';
$page_arr[$arr_count]['link'] = $url.$symb.'page='.($page-1);
$page_arr[$arr_count]['current'] = 0;
$arr_count++;
}
for ($x=$llimit;$x <= $rlimit;$x++)
{
if ($x <> $page)
{
$page_arr[$arr_count]['title'] = $x;
$page_arr[$arr_count]['link'] = $url.$symb.'page='.($x);
$page_arr[$arr_count]['current'] = 0;
}
else
{
$page_arr[$arr_count]['title'] = $x;
$page_arr[$arr_count]['link'] = $url.$symb.'page='.($x);
$page_arr[$arr_count]['current'] = 1;
}
$arr_count++;
}
if($page < $total_pages)
{
$page_arr[$arr_count]['title'] = 'Next';
$page_arr[$arr_count]['link'] = $url.$symb.'page='.($page+1);
$page_arr[$arr_count]['current'] = 0;
$arr_count++;
}
return $page_arr;
}
?>
and call it by
{LOOP: PAGES}{PAGES.title} {/LOOP: PAGES}
in an .html file..
it works perfectly but when I press the number 2 or next to get the next 20 records it jumps back to the first 20...
on the browser it reads http://siteurl/?cat=1&page=2
I can't figure out why.

Categories