Array_rand won't work

I used an example on PHP’s site to use in my script, but not sure what I’m doing wrong.

Here is the code

if (!empty($_POST['turnsUsed'])) {
	
	$query = "SELECT minerals.id, minerals.mineral FROM minerals";
	$input= getContent($query); //getContent is a function Im using to get the results from the database.
	
	$turnsUsed = $_POST['turnsUsed'];
	$x = 1; 
	while($x <= $turnsUsed) {
		
	//	$input = array("gold", "silver", "platinum", "bronze", "copper");
		$rand_keys = array_rand($input, 2);
		
		echo "<div><h2>Drilling attempt #$x you found</h2> ";
		echo rand(0,5)." pieces of ".$input[$rand_keys[0]]."</div>";
		$x++;
	} 
	$newTurns = $turns - $turnsUsed;
	$sql=$oDB->Prepare("UPDATE turns SET turns=:turns WHERE id=:userid");
	$sql->execute(array(':turns' => $newTurns, ':userid' => $uid));
}

The var dump of my array contains this (it looks a bit messed up so I believe the reason for my problem is here somewhere.)

array(10) { [0]=> array(4) { [“id”]=> string(1) “1” [0]=> string(1) “1” [“mineral”]=> string(6) “Acetin” [1]=> string(6) “Acetin” } [1]=> array(4) { [“id”]=> string(1) “2” [0]=> string(1) “2” [“mineral”]=> string(10) “Antimonium” [1]=> string(10) “Antimonium” } [2]=> array(4) { [“id”]=> string(1) “3” [0]=> string(1) “3” [“mineral”]=> string(8) “Argonite” [1]=> string(8) “Argonite” } [3]=> array(4) { [“id”]=> string(1) “4” [0]=> string(1) “4” [“mineral”]=> string(8) “Astatine” [1]=> string(8) “Astatine” } [4]=> array(4) { [“id”]=> string(1) “5” [0]=> string(1) “5” [“mineral”]=> string(9) “Merculite” [1]=> string(9) “Merculite” } [5]=> array(4) { [“id”]=> string(1) “6” [0]=> string(1) “6” [“mineral”]=> string(7) “Pergium” [1]=> string(7) “Pergium” } [6]=> array(4) { [“id”]=> string(1) “7” [0]=> string(1) “7” [“mineral”]=> string(9) “Silithium” [1]=> string(9) “Silithium” } [7]=> array(4) { [“id”]=> string(1) “8” [0]=> string(1) “8” [“mineral”]=> string(9) "Topaline " [1]=> string(9) "Topaline " } [8]=> array(4) { [“id”]=> string(1) “9” [0]=> string(1) “9” [“mineral”]=> string(10) “Tricyanate” [1]=> string(10) “Tricyanate” } [9]=> array(4) { [“id”]=> string(2) “10” [0]=> string(2) “10” [“mineral”]=> string(7) “Ritalin” [1]=> string(7) “Ritalin” } }

Im thinking of just doing another while loop and fill out a new array with only the mineral names instead of using the array above. Is that a better way to do it ?

What do you think the script should be doing?

What happens if turnsused is not a number? Since you haven’t validated it that field can contain anything at all. What information about your served will be exposed when a non number crashes your code?

I believe so, sort of.

array(10) { 
[0]=> 
 array(4) { ["id"]=> string(1) "1" [0]=> string(1) "1" ["mineral"]=> string(6) "Acetin" [1]=> string(6) "Acetin" }
[1]=>
 array(4) { ["id"]=> string(1) "2" [0]=> string(1) "2" ["mineral"]=> string(10) "Antimonium" [1]=> string(10) "Antimonium" }
[2]=>
 array(4) { ["id"]=> string(1) "3" [0]=> string(1) "3" ["mineral"]=> string(8) "Argonite" [1]=> string(8) "Argonite" } 
[3]=>
 array(4) { ["id"]=> string(1) "4" [0]=> string(1) "4" ["mineral"]=> string(8) "Astatine" [1]=> string(8) "Astatine" } 
[4]=>
 array(4) { ["id"]=> string(1) "5" [0]=> string(1) "5" ["mineral"]=> string(9) "Merculite" [1]=> string(9) "Merculite" } 
[5]=>
 array(4) { ["id"]=> string(1) "6" [0]=> string(1) "6" ["mineral"]=> string(7) "Pergium" [1]=> string(7) "Pergium" } 
[6]=>
 array(4) { ["id"]=> string(1) "7" [0]=> string(1) "7" ["mineral"]=> string(9) "Silithium" [1]=> string(9) "Silithium" } 
[7]=>
 array(4) { ["id"]=> string(1) "8" [0]=> string(1) "8" ["mineral"]=> string(9) "Topaline " [1]=> string(9) "Topaline " } 
[8]=>
 array(4) { ["id"]=> string(1) "9" [0]=> string(1) "9" ["mineral"]=> string(10) "Tricyanate" [1]=> string(10) "Tricyanate" } 
[9]=>
 array(4) { ["id"]=> string(2) "10" [0]=> string(2) "10" ["mineral"]=> string(7) "Ritalin" [1]=> string(7) "Ritalin" }
}

The array contains both numeric and associative keys.
My guess would be that the database has “id” and “mineral” fields, - but - the script will choke when it looks for “0” and “1” fields.

I wouldn’t bother with a while loop, I’d try to get the array to be associative keys only when it’s created.

I have some more code that I did not include above

Here is the whole file

<?php
include "template/header.php";

	$dbQuery = "SELECT * FROM turns WHERE userID = ".$uid;
	$data = getContent($dbQuery);
		foreach($data as $row) {
			$turns = $row['turns'];
		}


if (!empty($_POST['turnsUsed']) && $_POST['turnsUsed'] <= $turns) {

/*	
	$query = "SELECT minerals.id, minerals.mineral FROM minerals";
	$data = getContent($query);
	foreach($data as $row) {
		$mid = $row['id'];
		$mtype = $row['mineral'];		
	}
*/	
	if ($_POST['turnsUsed'] > 25) {
		$turnsUsed = 25;
	}
	else {
		$turnsUsed = $_POST['turnsUsed'];	
	}
	$x = 1; 
	while($x <= $turnsUsed) {
		
		$input = array("gold", "silver", "platinum", "bronze", "copper");
		$rand_keys = array_rand($input, 1);
		
		echo "<p>Drilling attempt #$x you found: ";
		echo rand(0,5)." pieces of ".$input[$rand_keys]."</p>";
		$x++;
	} 
	$newTurns = $turns - $turnsUsed;
	$sql=$oDB->Prepare("UPDATE turns SET turns=:turns WHERE id=:userid");
	$sql->execute(array(':turns' => $newTurns, ':userid' => $uid));
}
elseif ($_POST['turnsUsed'] > $turns) {
	echo "You don't have that many turns to spend.";
}
elseif ($_SERVER['REQUEST_METHOD'] == 'POST') {
	echo '<h2>You need to add a # of turns in the box below to mine for minerals.</h2>';
}

	echo '<p>You have a total of '.$turns.' turns! (max 25 turns each time)</p>';
	echo 'How many turns do you want to use for mining ? ';

	echo '<form method="POST" action="mining.php">
		<span class="style-1"><input type="text" name="turnsUsed"></span>
		<span class="style-1"><input type="submit" value="Start drilling!!"></span>
		</form>';

?>

I want the script to pick random minerals and a random amount for each mineral picked, then put it into the database. Its a mining script in a browser game I’m making lol. So they choose how many turns they wanna spend mining and each turn gives a random amount of a random material.

This is the function that is being used. I dont know how to change how it makes the arrays

function getContent($dbQuery) {
	include 'connection.php';
	
	$query = $dbQuery;
	$sql=$oDB->prepare($query);
	$sql->execute();
	$row = $sql->fetchAll();
			
	return $row;
}

http://php.net/manual/en/pdostatement.fetchall.php

public array PDOStatement::fetchAll ([ int $fetch_style [, mixed $fetch_argument [, array $ctor_args = array() ]]] )

fetch_style
Controls the contents of the returned array as documented in PDOStatement::fetch(). Defaults to value of PDO::ATTR_DEFAULT_FETCH_MODE (which defaults to PDO::FETCH_BOTH)

In this case you want

http://php.net/manual/en/pdostatement.fetch.php

PDO::FETCH_ASSOC: returns an array indexed by column name as returned in your result set

I usually setAttribute, but this should work.

$row = $sql->fetchAll(PDO::FETCH_ASSOC);
1 Like

Thanks, I will read that and see how far I get :smiley:

You need fred( … );


function fred($anyValueType=null, $title="No Title???", $print_r=true)
{
    $st_01 = "width:88%; margin:2em auto; 
              padding: 0.42em;
              background-color:#ffa; color:#800;";

    echo "<pre style='$st_01'>";
        echo $title .' ===> ';
        if($print_r) {
            print_r( $anyValType );
        }else{
            var_dump($anyValType);
        }
    echo '</pre>';    
}

$aTest = array(
    0 => '0',
    1 => '1',
    2 => '2',
    3 => '3',
);

fred($aTest);

Output

No Title??? ===> Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
)

1 Like

Im getting this after updating my database query function

No Title??? ===> Array
(
    [0] => Array
        (
            [id] => 1
            [mineral] => Acetin
        )

    [1] => Array
        (
            [id] => 2
            [mineral] => Antimonium
        )

    [2] => Array
        (
            [id] => 3
            [mineral] => Argonite
        )

    [3] => Array
        (
            [id] => 4
            [mineral] => Astatine
        )

    [4] => Array
        (
            [id] => 5
            [mineral] => Merculite
        )

    [5] => Array
        (
            [id] => 6
            [mineral] => Pergium
        )

    [6] => Array
        (
            [id] => 7
            [mineral] => Silithium
        )

    [7] => Array
        (
            [id] => 8
            [mineral] => Topaline 
        )

    [8] => Array
        (
            [id] => 9
            [mineral] => Tricyanate
        )

    [9] => Array
        (
            [id] => 10
            [mineral] => Ritalin
        )

)
1 Like

I updated my code with using rand() instead like this and it seems to work, but if I add more minerals in the database I will have to go back here and edit the numbers, so I will make a count. Is this a good or bad idea ?

	while($x <= $turnsUsed) {
		
		$dbQuery = "SELECT minerals.id, minerals.mineral FROM minerals";
		$input = getContent($dbQuery);
		//$input = array("gold", "silver", "platinum", "bronze", "copper");
		//$rand_keys = array_rand($input[0], 2);
		$rand_keys = rand(1,10);
		
		echo "<p>Drilling attempt #$x you found: ";
		echo rand(0,5)." pieces of ".$input[$rand_keys][mineral]."</p>";
		$x++;
	}

Thanks everyone, I got it working as expected. (I think) This is the full code Im using. Anything wrong with the code or something I should do different ? One of the problems I see is alot of DB queries and by adding numbers with a positive + in front will give them more turns when they are out of turns lol.

<?php
include "template/header.php";

	$dbQuery = "SELECT * FROM turns WHERE userID = ".$uid;
	$data = getContent($dbQuery);
		foreach($data as $row) {
			$turns = $row['turns'];
		}


if (!empty($_POST['turnsUsed']) && $_POST['turnsUsed'] <= $turns) {


		
	if ($_POST['turnsUsed'] > 25) {
		$turnsUsed = 25;
	}
	else {
		$turnsUsed = $_POST['turnsUsed'];	
	}
	$x = 1; 
	while($x <= $turnsUsed) {
		
		$dbQuery = "SELECT minerals.id, minerals.mineral FROM minerals";
		$input = getContent($dbQuery);
	
		$rand_keys = rand(0,9);
		$amount = rand(0,5);
		
		echo "<p>Drilling attempt #$x you found: ";
		echo $amount." pieces of ".$input[$rand_keys][mineral]."</p>";
		$x++;
		
		$sql=$oDB->Prepare("UPDATE bank SET amount=amount+:amount WHERE minerID=:minerID AND userID=:userID");
		$sql->execute(array(':minerID' => $input[$rand_keys][id],':amount' => $amount, ':userID' => $uid));
	} 
	$newTurns = $turns - $turnsUsed;
	$sql=$oDB->Prepare("UPDATE turns SET turns=:turns WHERE id=:userid");
	$sql->execute(array(':turns' => $newTurns, ':userid' => $uid));
}
elseif ($_POST['turnsUsed'] > $turns) {
	echo "You don't have that many turns to spend.";
}
elseif ($_SERVER['REQUEST_METHOD'] == 'POST') {
	echo '<h2>You need to add a # of turns in the box below to mine for minerals.</h2>';
}

	echo '<p>You have a total of '.$turns.' turns! (max 25 turns each time)</p>';
	echo 'How many turns do you want to use for mining ? ';

	echo '<form method="POST" action="mining.php">
		<span class="style-1"><input type="text" name="turnsUsed"></span>
		<span class="style-1"><input type="submit" value="Start drilling!!"></span>
		</form>';


?>

With the first query you’re only using the “turns” field so only select the “turns” field. If you’re using PDO it has a fetchall method which can grab the result set in one hit - eliminating a loop. How many rows do you expect to be returned by the first query.

Is the value for $uid coming from session data? If it’s not, make sure it’s validated, if it’s numeric an easy way is to typecast it as an integer, any non-numeric value will be changed to 0.

With the second query, do you expect to act on the same mineral twice? If not consider moving the second query outside of the while loop.

For the third query you might want to consider building a bulk update query then the execution of that query could be moved outside of the loop, meaning only hitting the DB once there.

You should consider wrapping all the from (including) the first query down to the end of the main loop (including) the third query in a transaction

1 Like

Thanks for your help. I will do what you say. The first query I just need the amount of turns. the $uid is from the session data. I only have 10 different minerals for now in the database, I just wanted the user receive some random amounts of some random minerals so for now I dont mind if the same one appear twice, but I may change that later.

Would I be using an array to bulk it up ?

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.