Jump to content
MakeWebGames

Jax

Members
  • Posts

    19
  • Joined

  • Last visited

  • Days Won

    2

Everything posted by Jax

  1. Far be from me to put people off the big frameworks, consider writing it in PHP ... plain old-fashioned PHP, no framework, in fact with care you can get away without composer.json or indeed a vendor folder - not recommended however assuming you want to write tests (and you do... trust me), not to mention making autoloading a breeze! I've seen far too many instances of ""Laravel"" programmers that simply cannot write raw PHP, they have been too accustomed to using all the bells and whistles which Laravel provides. Don't get me wrong, I like the bells and whistles, but a) they are not too difficult to write for your use case, and b) sometimes you have to write real-world code that simply doesn't fit into the patterns that can be forced upon you with these large frameworks. The same holds true to a lesser extent for the other large frameworks - and in fact I attended a fascinating talk in Birmingham last year IIRC on framework agnostic code - ie your code or domain logic was separate from the framework making it simple to switch between Symfony, Laravel, CodeIgniter for example. Perhaps you feel that some sort of basic framework is required, in which case have a look at Slim, it's small, fast, and very easy to use. Best of all, you can relatively easily convert your controllers for use in other frameworks as it uses little more than PSR-7 messaging. For CSS, I'm a fan of Tailwind and for Javascript, Alpine seems to fit the bill nicely, though both can take a bit of getting used to. If you do go the Laravel route, perhaps have a look at Livewire. It's becoming a very popular addition, and is starting to have the feel of React or Vue without the complexities. Laravel can be beneficial from a career point of view, I use it commercially daily, though I work with legacy code - no framework in sight - equally as much. I suspect that the legacy knowledge is oddly more useful the further up the career ladder you get - but your mileage may well vary. Whatever you decide on - stick at it for a while, learn the ins and outs, the little "gotcha's", find the sweet spot, the ideal position in the market for that framework, and keep experimenting with it. Before long you will become accustomed to its ways and be able to push its boundaries forward as well as your own.
  2. Jax

    Anti Bot

    From Google's introduction to the "No CAPTCHA reCAPTCHA". Might be worth investigating a different route!
  3. Crons are really not needed when simple arithmetic covers it nicely. You could, for example, have different rates per user by storing the APR (annual percentage rate) and the date deposited in the user table. After that, it's just simple case of basic arithmetic to determine the PV (present value). Example: -- assuming the date deposited is a integer from the PHP function time(): $principal = $ir["bankmoney"]; $apr = $ir["apr"]; $daysSinceDeposited = (time() - $ir["deposited"]) / 86400; /* 86400 seconds in a day */ $dailyRate = pow(1 + $apr / 100, 1 / 365.2425); /* 365.2425 days in a year */ $presentValue = pow($dailyRate, $daysSinceDeposited) * $principal; So assuming an APR of 40%, a principal of $100, after 10 days we'd have a computer present value of $100.925, after 100 days it would be $109.650, after 1 year it would be $140.00 (exactly 40% APR). Taking money out of the bank would necessitate computing the present value, subtracting the withdrawal amount and placing the result in your bankmoney field, deposits are done by storing the present value plus the deposit amount in the bankmoney field.
  4. Clearly explaining problems in not one of your finest talents. In order for people to help you - both now and in the future, it really does help if you provide a *lot* of information. Start with the basics. McCodes engine - we know (or assume we know given the forum ...) that's a good start however if memory serves me, McCodes never had a PDO database class, only a MySQL and MySQLi class, therefore you are already presenting a problem in code that is not "out of the box". PDO in general is nice and simple:   $stmt = $db->prepare("SELECT field1, field2, field3 FROM table WHERE fieldN = :expr"); $stmt->execute(['expr' => "search-expression"]); $row = $stmt->fetch();   No at all complex, and reasonable safe from a number of potential attack vectors. Now if you presented the code *you* use, then other people might be able to spot where the error lies - as it stands, we haven't a clue. You say you've tried too many different things to list - no, I suspect that is laziness. Even Guest will have the decency to actually point people to the code he's having problems with (which happens surprisingly frequently) - so please give us a better bit of information. I can assure you that your code is not special, no matter what you think - people have been modifying the venerable McCodes platform for years now, there's seldom anything new or indeed complex, so show us the snippet of code that you think is failing, show us the input variables ($_GET / $_POST etc) to it, show us the output and show us what the expected output should be. I'd also suggest that unless you are using 100% stock McCodes tables, you present the data definition (SHOW CREATE TABLE xxx) of the relevant tables. Remember, asking questions is about solving problems - if you can't present sufficient information for people to address the problem - the problem doesn't go away. *If*, on the off-chance that you have actually solved this, then I'd suggest that you actually present the problem *and* the solution so that anybody else struggling with a similar issue can learn from your experiences rather than find yet another useless topic on MWG.  
  5. Alternatively, you could look at the problem from the point of view of what actually needs to be done. Consider the implementation of the inventory table: inv_id : The unique ID of this inventory (user/item pair) (automatically generated) inv_itemid : The item ID itself inv_userid : The user ID (owner of said item) inv_qty : The quantity owned   Now to add to this we can do the following: /** * Add an item to a user's inventory * * $user <integer> (or numeric string) The ID of the user to give an item to * $item <integer> (or numeric string) The ID of the item to add * $qty <integer> (or numeric string) The quantity of $item to give to $user **/ function give($user, $item, $qty=1) { global $db; // Update the existing inventory row $sql = <<<SQL UPDATE `inventory` SET `inv_qty` = `inv_qty` + $qty WHERE `inv_itemid` = $item AND `inv_userid` = $user SQL; $db->query($sql); // If nothing was changed, add a new row if (!$db->affected_rows()) { $sql = <<<SQL INSERT INTO `inventory` (`inv_itemid`, `inv_userid`, `inv_qty`) VALUES ($item, $user, $qty) SQL; $db->query($sql); } }   Purists may point out a potential race condition however this cannot be circumvented cleanly without altering the database itself. However, it does perform more efficiently than the builtin item_add function which suffers from both race conditions and potential data loss. The key to figuring out Mccodes is to learn how the database is structured; it's not elegant I'll admit, but it is a beginning. With a little care, you can easily make it into something really special. Please note, the above function is intentionally not safe from SQL injection -- I assume that however, most if not all people are perfectly capable if ensuring that only integers or at least strings passing ctype_digit() as passed to it.
  6. % is the key - a little simple math. Example: assuming we want to limit the potential range of values present in a GET variable to 34,359,738,368 (32^7), we could cloak the number 1 as :   (1 * 5513821138855354025239443855326722937375776141979) % 34359738368 = 28633821851   Hardly an obvious result. The reverse is equally easy:   (28633821851 * 24455685011) % 34359738368 = 1   As for how did I arrive at the two large numbers?   5513821138855354025239443855326722937375776141979 is simply a 50 digit prime while 24455685011 is its modular inverse with respect to 34359738368   With these numbers, you can safely encode from 1 to 34359738367 *without repetition, and due to the size of the large prime, and the fact that both it and your range value will be secret to your site, it becomes impossible with existing hardware to decode in any reasonable amount of time. Obviously, you would need to pick a different large prime though those are easy to generate in this type of range, and the limit can be set to something like 2^32 without any problem. I'd probably further this by adding in perhaps something from session data - the ID perhaps, as well as time ensuring that the sequence of numbers that a player would see is not deterministic *without* aid. POST data can be manipulated just almost as easily as GET data so I'd favour cloaking data through POST in this way. It certainly works for the large social networks, it can easily be adapted to smaller projects. Complex? No - This is high school maths - something that can be easily learnt. Further example: Given a prime of 65323, a limit of 100, this yields a modular inverse of 87 which if we look at the potential output of numbers:   1 * 65323 % 100 = 23 2 * 65323 % 100 = 46 3 * 65323 % 100 = 69 4 * 65323 % 100 = 92 5 * 65323 % 100 = 15 6 * 65323 % 100 = 38 7 * 65323 % 100 = 61 8 * 65323 % 100 = 84 9 * 65323 % 100 = 7 10 * 65323 % 100 = 30 11 * 65323 % 100 = 53 12 * 65323 % 100 = 76 13 * 65323 % 100 = 99 14 * 65323 % 100 = 22 15 * 65323 % 100 = 45 16 * 65323 % 100 = 68 17 * 65323 % 100 = 91 18 * 65323 % 100 = 14 19 * 65323 % 100 = 37 20 * 65323 % 100 = 60 21 * 65323 % 100 = 83 22 * 65323 % 100 = 6 23 * 65323 % 100 = 29 24 * 65323 % 100 = 52 25 * 65323 % 100 = 75 ... 90 * 65323 % 100 = 70 91 * 65323 % 100 = 93 92 * 65323 % 100 = 16 93 * 65323 % 100 = 39 94 * 65323 % 100 = 62 95 * 65323 % 100 = 85 96 * 65323 % 100 = 8 97 * 65323 % 100 = 31 98 * 65323 % 100 = 54 99 * 65323 % 100 = 77   Looks pretty random to me.
  7. But surely, as both $_GET and $_POST variables are passed as strings or arrays, unless god forbid you modify them, there is no need for the is_int my random friend. $id = array_key_exists('id', $_POST) && ctype_digit($_POST['id']) ? $_POST['id'] : false; # note the === to detect ONLY false, and not zero if ($id === false) { header('HTTP/1.1 400 Bad Request'); exit; } array_key_exists() is a sensible option as isset() or empty() can produce unexpected results. ctype_digit() will type check first; it expects a string before checking the contents and only returning true if the value is a string of possibly 0 leading digits. Of course, you still have to range check, and blindly casting to an int can yield unusual albeit edge case results. Using the more correct in this case === rather than ! allows the use to pass zero without the script terminating early.
  8. Look at the error, it is pretty self explanatory. PHP Warning: (so not serious then...) Unknown: (Got to love PHP for not knowing what the problem is....) open(/home/users/web/b2468/nf.str8klowninentcom/public_html/cgi-bin/tmp/sess_9cf25349dc9bc2480c2948579d8066ee, O_RDWR) failed: (okay, that looks like a session file) No such file or directory (Obvious). So checkout your ability to save session from PHP - make sure the folder is accessible, and writeable by PHP / your web server (depends to an extent which one is the "user" when it comes to reading and writing these files)
  9. rand() uses the system's own random number generator tools which are not always ideal, mt_rand() uses a decent algorithm that in general produces better randomness. mt_rand() is also reportedly faster, though I've never found the need to generate sufficient random numbers individually to warrant speed testing it. As an analogy, I'd compare rand() to an old dice that has been the family for a while, it has become slightly worn, has a couple of rough edges, and throws a 6 slightly more than 16.6% of the time. mt_rand() on the other hand is a nice shiny new dice straight from the manufacturer and has been thoroughly tested with a micrometer by a casino pit boss. Not entirely accurate, but sufficient for MWG purposes.
  10. @AMTheMasterGeneral The chances of winning make it difficult for players to see any benefit from playing. If you consider that slot machines often have payout percentages set to 95%, so a player playing 100 times at a cost of $10 per game would have in their pocket at the end of the day 95% * 100 * $10 or $950. This suggests to the players that they may win more whereas your payout would appear to be 1%. Not very enticing.   Why? How many do you need to determine if somebody has won or not?  No need, at only a 1% payout, they will quickly run out of money. From a full featured lottery I might initially agree, though again I see no need for crons. There are plenty of ways to avoid their use.  He did and in a lot more elegant method than any array. mt_rand(1, 2) is 1 50% of the time mt_rand(1, 3) is 1 33.333% of the time mt_rand(1, 4) is 1 25% of the time etc etc or: mt_rand(1, 100) is less than 100 99% of the time mt_rand(1, 100) is less than 99 98% of the time mt_rand(1, 100) is less than 98 97% of the time etc etc. it's a lot more manageable from the point of view of supporting code to use the simplest expression possible, in this case it could be argued that storing the upper bound in a configuration file / settings table would suffice rather having to edit an array of 1's and 0's every time.   jm2c
  11. empty() is the problem as that returns true if the input is "0" (zero). See http://php.net/manual/en/function.empty.php in particular the return values section. Your tests are: $value = isset($_POST['key']) && is_numeric($_POST['key']) ? abs(intval($_POST['key'])) : ' '; I'd probably replace with $value = array_key_exists('key', $_POST) && ctype_digit($_POST['key']) ? $_POST['key'] : ' '; for positive integers, $value = array_key_exists('key', $_POST) && is_string($_POST['key']) ? $_POST['key'] : ' '; for strings and $value = array_key_exists('key', $_POST) && is_numeric($_POST['key']) ? $_POST['key'] : ' '; for numbers (negative integers, or decimal values). This is slightly stricter and performs better type checking as well as using the in this instance more correct array_key_exists rather the issset. Be careful the the default values as a single whitespace character is probably not what you want here. is_empty often catches out people, there are very few places I've found it to be the correct test to use. See http://php.net/manual/en/function.empty.php in particular.
  12. Depends on the language. PHP - MySQLi where possible, MySQL if nothing else available though never PDO Python - MySQL Perl - Mostly PostgreSQL Though I also use a variety of hybrid databases KV/EAV stores and document stores.
  13. Why don't you try using a color scheme triadic color scheme - (for example - http://colorschemedesigner.com/csd-3.5/#1K32IezpZFpLE) or tetradic color scheme? That way the colors will mix with each nicely as a starting point. Designers will no doubt argue the difference, however I find it makes for a decent starting point.
  14. You state that you are expecting a positive input, and the discussion this far seems to assume we are also talking about integers, yet you state that both "hello" and 45.6 are valid integers. How can "hello" be a valid input? The initial point I made pointed out the flaw of using (int)sprintf('%u', $var); as while the result is an integer, it can be a highly unlikely value. Testing your code suggests that you perhaps need to look a little closer at it. After all what is the desired effect here? Users will generally fill out forms correctly, though some mistakes must be prevented. Hackers will try to subvert your form by pushing highly unusual data into your system. Surely the latter of these must be blocked rather than blindly accepted. Example code: https://node86.com/pastebin/5b0s72b And output: https://node86.com/pastebin/c43q6 While your code is not wrong, it simply makes assumptions about the input which ~may~ come back and bite you. Correct type checking, type conversion and range checking is a necessary fact of almost all applications, unfortunately, with PHP this can be made tricky as people fall into common basic mistakes and worse make blind assumptions about internal functions accepting their documentation as-is without running sufficient checks. A good hacker or pen tester will understand the flaws in the language and how people make simple mistakes with sanitization enabling them to circumvent your system. BTW, the 075 test caught me out, I'm still not 100% convinced on how to handle that one cleanly outside of using regex to check the input, however then you run into a range of other interesting problems.
  15. No, it doesn't - However if you think that is the same ... I'll accept that. What's your game URL ? :D
  16. [MENTION=70600]SHPXLBH[/MENTION] Your so-called ""sanitization"" code leaves a lot to be desired. Lack of type checking can lead to potentially unexpected values; for example: Given $_POST['var'] = "-1"; echo (int)sprintf('%u', $_POST['var']); yields 9223372036854775807 assuming a 64-bit machine, while echo sprintf('%u', $_POST['var']); yields 18446744073709551615. Passing an array instead of an string again yields unexpected values: Given $_POST['var'] = array(); echo (int)sprintf('%u', $_POST['var']); yields 0, while $_POST['var'] = array(1,2,3) yields 1. Not unexpectedly, $_POST['var'] = array(array()); yields 1; Within any program, you should always know the type of expected input; with PHP, $_GET and $_POST elements are either strings or arrays. If it's a string, and you are expecting an integer, then surely ctype_digit() is the optimal check, though obviously range checking is required. I would have thought that something more akin to: // make sure the expected verb has been used if ($_SERVER['REQUEST_METHOD'] == 'POST') { // setup the range limits $var_min = 0; $var_max = 100; // check the given variable has been provided, is the correct type // AND fits within a sane range if (array_key_exists('var', $_POST) && ctype_digit($_POST['var']) && ($_POST['var'] >= $var_min) && ($_POST['var'] <= $var_max)) { $var = $_POST['var']; // do something with $var - no real need to cast it to an int here } else { // bad data header('HTTP/1.1 400 Bad Request'); exit; } } Of course, this type of problem is always open to interpretation, a lot of games developed through these pages as you have pointed out in other topics are easily inject-able, however lack of proper type checking as in this instance is equally a recipe for disaster. While I'm sure your code would correctly handle the case of say, transferring $9223372036854775807 between accounts, I know a lot of the code presented here fails this most basic of check.
  17. Jax

    "Cronless crons"

    Why run an extra query to fix something that you have just run? Assuming you have; for example: UPDATE users SET energy = energy + max_energy / 6; as one query, you would probably think that: UPDATE users SET energy = max_energy WHERE energy > max_energy; is suitable to correct any problems with the first query, yet you can kill two birds with one stone with the rather elegant: UPDATE users SET energy = LEAST(max_energy, energy + max_energy / 6); LEAST() and GREATEST() are handy functions that should not be neglected. Why do it this way? One query, means less context switching between PHP and SQL, it means less time with the table, or pages within the table being locked thus potentially preventing anybody else from accessing these records; being SQL, it prevents race conditions when it would be possible for a user to actually access more energy than their theoretical maximum energy. etc. etc.
  18. I am looking for some relatively simple content writing; essentially made up of a number of levels of detail, for example: 1 Name: Personal Goals | +-- 1.1 Name: Build a House | 1.1 Description: You need a place to store all your gear | | | +-- 1.1.1 Name: Build the foundations | | 1.1.1 Description: Your house needs a good solid base to stand upon. | | 1.1.1 Time: 4 minutes | | | +-- 1.1.2 Name: Build the walls | | 1.1.2 Description: All good houses need 4 solid walls | | 1.1.1 Time: 12 minutes | | | +-- 1.1.3 Name: Fit the Roof | 1.1.3 Description: Finally, fit the roof to keep your gear dry. | 1.1.1 Time: 20 minutes | +-- 1.2 Name: Create the Garden 1.2 Description: Having built your house, now you need a garden. | +-- 1.2.1 Name: Remove the weeds | 1.2.1 Description: ... | 1.2.1 Time: 6 minutes | +-- 1.2.2 Name: Double dig the ground | 1.2.2 Description: ... | 1.2.1 Time: 12 minutes | +-- 1.2.3 Name: Dig in the manure | 1.2.3 Description: ... | 1.2.1 Time: 24 minutes | +-- 1.2.4 Name: Plant the seeds 1.2.4 Description: ... 1.2.1 Time: 48 minutes etc. There are many more details to be filled out at each level, however I'm happy to fill those in myself for now. I'm looking for 4 major top levels, with up to 4-12 second level entries per top level, with each second level having 3-5 low level components so there's potentially a decent bit of story-telling going on here. Genre - I think for the moment, I will go with crime for simplicity, however if you have an idea with a decent amount of detail, I'm open to suggestion. Think you are up for the job? Create a small sample and estimate how many complete entities you can provide along with an idea of price and drop me a line.
×
×
  • Create New...