PHP question on while query - php

Could someone help me figure out how to do this.
I have a game where a player can use potions to enhance their abilities.
This is on a timer which works fine. However Im now looking to add to this query when the player uses 2 different type of potions. I can get it to work but not 100% how I wish.
Player uses potion 1 and their stats are boosted by 20% for 20minutes.
Player then uses potion 2 and their stats are boosted by 60% for 20minutes.
With my code at the moment
$check = sprintf("SELECT time,strmod FROM `effects` WHERE `userid` = %u", $userid);
$exe = mysql_query($check);
while($bonus = mysql_fetch_array($exe))
{
$last = $bonus['time'];
$strmod=$bonus['strmod']);
It will display the users bonus (base strength in this example is 2,364,195)
Potion 1 boost your base strength to 2837034 (+20%)
Potion 2 boost your base strength to 3782712 (+60%)
Is there a solution where I can get the second 60% potion to take into account the bonus received from the 1st potion. So 60% of 2837034 rather than 2364195. Before I consider recoding the whole thing :D
I hope thats clear bit hard to explain.
Thanks

I presume the database table contains the list of potions in effect. Try something which keeps the value over the while loop...
$multiplier = 1;
while($bonus = mysql_fetch_array($exe))
{
$last = $bonus['time'];
$strmod=$bonus['strmod']);
$multiplier += $strmod/100; // convert from percent to decimal
}
$currStrength = $multiplier*$baseStrength;

Probably not the way your doing it, since your not recording the original players HP, you just have the current (after modifiers have been applied) HP.

Related

Search in MySQL with permutations

I need help.
I have a table where only two columns are: ID and NAME and these data:
ID | NAME
1 HOME
2 GAME
3 LINK
And I want show e.g. row with name: HOME if user search: HOME or OMEH or EMOH or HMEO, etc... - all permutations from word HOME.
I can't save to mysql all these permutations and search in this columns, because some words will be a too big (9-10 chars) and more than 40 MB for each 9 chars words.
One way to solve this problem is to store the sorted set of characters in each name in your database as an additional column and then sort the string the user inputs before searching e.g. database has
ID NAME CHARS
1 HOME EHMO
2 GAME AEGM
3 LINK IKLN
Then when searching in PHP you would do this:
$search = 'MEHO'; // user input = MEHO
$chars = str_split($search);
sort($chars);
$search = implode('', $chars); // now contains EHMO
$sql = "SELECT ID, NAME FROM table1 WHERE CHARS = '$search'";
// perform query etc.
Output
ID NAME
1 HOME
This sounds like a "please do my homework for me" question. It is hard to conceive what real world problem this is applicable to and there is no standard solution. It is OK to ask for help with your homework here, but you should state that this is the case.
more than 40 MB for each 9 chars words
Your maths is a bit wonky, but indeed the storage does not scale well. OTOH leaving aside the amount of storage, in terms of the processing workload it does scale well as a solution.
You could simply brute-force a dynamic query:
function mkqry($word)
{
$qry="SELECT * FROM yourtable WHERE 1 ";
$last=strlen($word);
for ($x=0; $x<$last; $x==) {
$qry.=" AND word LIKE '%" . substr($word, $x, 1) . "%'";
}
return $qry;
}
However this will always result in a full table scan (slow) and won't correctly handle cases where a letter occurs twice in a word.
The solution is to use an indexing function which is independent of the order in which the characters appear - a non-cryptographic hash. An obvious candidate would be to XOR the characters together, although this only results in a one character identifier which is not very selective. So I would suggest simply adding the character codes:
function pos_ind_hash($word)
{
$sum=0;
for ($x=0; $x<$last; $x==) {
$sum+=ord(substr($word, $x));
}
return $sum;
}
function mkqry($word)
{
$qry="SELECT * FROM yourtable WHERE 1 ";
$last=strlen($word);
for ($x=0; $x<$last; $x==) {
$qry.=" AND word LIKE '%" . substr($word, $x, 1) . "%'";
}
$qry.=" AND yourtable.hash=" . pos_ind_hash($word);
return $qry;
}
Note that the hash mechanism here does not uniquely identify a single word, but is specific enough to reduce the volume to the point where an index (on the hash) would be effective.
Multiplying rather than adding would create fewer collisions but at a greater risk of overflowing (which would create ambiguity between implementations).
But both the hash and the single character LIKE only reduce the number of potential matches. To get the query to behave definitively, you need to go further. You could add an attribute to the table (and to the index with the hash)containing the string length - this would be more selective (i.e. improve effectiveness of the index) but still not definitive.
For a definitive method you would need to specify in your query that the data does NOT contain characters which are NOT in the word you are looking for.
The wrong way to do that would be to add a loop specifying "AND NOT LIKE....".
A valid way of doing that would be to add a test in the query which replaces all the letters in the table attribute which appear in the word you are searching for which results in a zero length string.

PHP - Generating random integers within specified range from a key

I have a set of questions with unique IDs in a MySQL database.
Users also have a unique ID and are to answer these questions and their answers are saved in the database.
Now, I want users to get 5 non-repeating uniquely and randomly picked questions from the pool of available ones (let's say 50) based on users ID. So when a user with id 10 starts answering his questions, but stops and wants to return later to the same page, he will get the same questions as before. A user with id 11 will get a different random set of questions, but it will always be the same for him and different from all other users.
I found that random.org can generate exactly what I need with their sequence generator that generates a random sequence of numbers based on provided ID:
https://www.random.org/sequences/?min=1&max=50&col=1&format=plain&rnd=id.10
But I would like the generation to be done locally instead of relying random.org API.
So, I need to generate 'X' unique random integers, within specified range 'Y' that are generated based on supplied integer 'Z'. I should be able to call a function with 'Z' as parameter and receive back the same 'X' integers every time.
I need to know how to replicate this generation with PHP code or at least a push or hint in a direction of a PHP function, pseudo-code or code snippet that will allow me to do it myself.
Thank you in advance!
Why reinvent the wheel
mt_srand(44);
for ($i=0; $i < 10; $i++) echo mt_rand(). "\n";
echo "\n\n";
mt_srand(44);
for ($i=0; $i < 10; $i++) echo mt_rand(). "\n";
result
362278652
928876241
1914830862
68235862
1599103261
790008503
1366233414
1758526812
771614145
1520717825
362278652
928876241
1914830862
68235862
1599103261
790008503
1366233414
1758526812
771614145
1520717825
Generate your random numbers at the beginning and save it in a session. That way the random numbers for that user is always known and you can know what id of question you should go back to by looking it up in the session.
Cheers
you can get random $w array values. try this code as example and change with your logic.
$w = array('0'=>11,'1'=>22,'2'=>44,'3'=>55,'4'=>66,'5'=>88);
$str = '';
for($i=0;$i<5;$i++) {
$str.= $w[rand(0,5)];
}
As this article suggests, you could use a non-repeating pseudo random number generator. Only problem would be to generate a primnumber that is atleast 2x as big as the upper-bound for IDs and satisfies the condition p = 3 in the ring Z4. Though there should be big-enough primnumbers matching the conditions on the net for free use.
Due to my lack of experience with PHP i can only provide pseudocode though.
int[] generateUniqueRands(int id , int ct)
int[] res
const int prim//the primnumber described above
for int i in [0 , ct[
res[i] = ((id + i) * (id + i)) % prim
return res
Note that this algorithm basically works like a window:
id = x set = [a , b , c , d]
id = x + 1 set = [b , c , d , e]
...
If you wish to avoid this kind of behavior just generate a unique random-number from the id first (can be achieved in the same way the set of random numbers is generated).
When the user with ID 10 opens the page for the first time, use rand() to generate random numbers then store them into a cell in the users table in database. So the user with id 10 has the rand() numbers stored.
For example the users table has id, rand_questions.
Check if the rand_questions is empty then update with the new random numbers generated, else you get the numbers from the database.

List to URL Parameter

I have a bunch of integers which act as ID's within an ArrayList in my Android application.
This list of id's can be of any amount ranging from 0 - x. These id's are to identify players in a match. What I want is to send data to the web service, telling it that players 1,2 and 3 are on team 1 and players 4,5 and 6 are on team 2.
How best can I construct the URL with the above and how do I properly "expect" and "intercept" these parameters on the server side? I am using PHP.
So far I can think of the following:
$p1 = $_GET['p1'];
$p2 = $_GET['p2'];
$p3 = $_GET['p3'];
But as you can probably guess, that's really bad as I don't know how many people will be in team 1 and how many people in team 2. And further...how to seperate them.
Any ideas?
You can do a simple list of players in each teams :
// $_GET['team1'] = '1,2,3';
$team1 = $_GET['team1'];
$team1 = explode(',', $team1);
// $_GET['team2'] = '4,5,6';
$team2 = $_GET['team2'];
$team2 = explode(',', $team2);
Then you have an array per team, containing the players id.
Hope it helped !
EDIT:
Care of query maxlength here is a link :
Please note that PHP setups with the suhosin patch installed will have
a default limit of 512 characters for get parameters. Although bad
practice, most browsers (including IE) supports URLs up to around 2000
characters, while Apache has a default of 8000.
To add support for long parameters with suhosin, add
suhosin.get.max_value_length = in php.ini

Random dosieid number that is not used

I'm trying to generate a unique "dosieid" number for my web site. My web site is a human resources program solution, in that program users create dosie of their workers in their firm ...random dosieid needs me so when user creating dosie in field dosieid automatically show the dosieid-s that are not used before...the dosieid that don't exist in database. In other case I would use auto increment but in this case dosie is not created yet. And in form dosieid must be option to change the number if random is not fine with a user. One more hint the numbers must bee from 1 to 9999. Can someone help me? I have try many codes but I have not find something like one with this spec.
This is what I have do so far. It gets the random number but I don't know how to compare that random number with database row "dosieid" ?
$id_num = mt_rand(1,9999);
$query = "SELECT dosjeid FROM albums";
$result = mysql_query($query) or die(mysql_error());
while($account = mysql_fetch_array($result)){
if ($id_num == $account['id']){
$id_num = mt_rand(1,9999);
}
}
echo"$id_num<br>";
This is extraordinarily convoluted... why is an auto-incrementing number not enough? This code would also never work properly. If for whatever reason you HAVE to use a random number, then you'd do it like this:
while(true) {
$id_rand = mt_rand(1,9999);
$result = mysql_query("SELECT count(*) FROM albums WHERE dosjeid=$id_rand") or die(mysql_error());
$row = mysql_fetch_row($result);
if ($row[0] == 0) {
break; // our random number isn't in the database, so exit the loop
}
}
However, here's some problems with this:
1) You'll get an infinite loop when you reach 9999 dosie records
2) The more records there are in the database, the longer this loop will take to find a "vacant" slot. As you get closer and closer to 9999 records, you'll be taking a LONG time to find that one empty slot
3) If you're trying to "cloak" the IDs of anyone member so that users can't simply increment an ID parameter somewhere to see other people's records, there's FAR FAR FAR better/easier ways of doing this, such as encrypting the ID value before sending it out to clients.
Use a auto-increment number as your primary key and an additional display id with the UNIQUE attribute as the ID shown to the user. This way you have a unique ID for your internal processing and a display ID that can be easily changed.
This is a terrible design. You should either:
not let users create the dosieid (create it yourself, give it to them after record created)
Try to create a stub record first with an assigned dosieid, and then update it with information
or use UUIDs, which requires a much bigger range than 1-9999
Even if you check that the number was unique, in between the time when you check it and the time you insert the record someone else may have taken it.
And under no circumstances should you find an empty id by picking numbers at random. This makes your program execution time non-deterministic, and if you eventually get 5000 employees you could be waiting a long time.
Also, This range is way too small for a randomness requirement.
You may also want to read about number only hashes (check upon the algorithm's collision rate) - php: number only hash?
function doesIdExists($id)
{
$query = "SELECT dosjeid FROM albums";
$result = mysql_query($query) or die(mysql_error());
while($account = mysql_fetch_array($result))
{
if ($id_num == $account['id'])
return true; /* The id is taken */
}
return false; /* Not taken */
}
$recNotAdded = true;
while($recNotAdded)
{
$rand = mt_rand(1,1000); //Whatever your numbers
$doesExist = doesIdExists($rand);
if(!$doesExist)
{
/* Add to DB */
$recNotAdded = false;
}
}

Creating a secuence of characters from a secuence of numbers in PHP

i have a database with many items in there, by the moment my users retrive info from the database using a simple php script who use GET parameters, like www.mypage.com/post.php?id=123432
Well at the beginning it was all fine, but know i have Ids that are very big (10000000). So at this point i dont my users to have that longs urls, so i think that changing the secuence of number for a secuence of leters will do the think, like post.php?id=XFBJ and then the php script knows that is the id=11223256437 for example. Any ideas of how to do this? Thanks!
I suppose you could do very simple trick to achieve that. Treat ID from URL as 36-based number and convert it to 10-based number before retrieving from database.
$_GET['id'] = '5yc1s';
$id = base_convert($_GET['id'], 36, 10); // 10000000
// SELECT ... FROM ... WHERE id = :id [id = $id]
And when you want to display a link do the opposite:
$id = 10000000;
$urlId = base_convert($id, 10, 36); // 5yc1s
// ...?id=$urlId
EDIT: Oh, base_convert() has upper limit of 36 (a-z0-9), not 32 - that makes your links even shorter. Of course you could write your own function that could convert up to 62-based numbers (a-zA-Z0-9) — that's a reasonable upper limit (of course even higher are available). Writing such a function is really easy.

Categories