Jump to content

Jacques1

Members
  • Posts

    4,207
  • Joined

  • Last visited

  • Days Won

    209

Everything posted by Jacques1

  1. Initialization values of properties are evaluated at compile-time, so you can't use arbitrary expressions (you're mostly limited to constant values). To get around this, you can use a constructor to set the property value when the object is created: <?php class Demo { protected $len; public function __construct() { $this->len = strlen('MY_TEXT'); } public function getLen() { return $this->len; } } $demo = new Demo(); var_dump($demo->getLen());
  2. There's really no such thing as “data sanitization”. Security always depends on the specific context. The same data may be entirely harmless in one context and cause horrible damage in another context. So there isn't any universal function to make all input safe once and forever. What you should so is parse the string and then insert the extracted numbers into your database system using prepared statements. Like Psycho already said, comma-separated values don't belong into an SQL table. One field is for one value (of course there are always exceptions, but this is a good rule of thumb). Since prepared statements reliably prevent SQL injections, you won't have any security problems in your database-related code. If you use the data in a different context, you should use escape it using an appropriate function for this specific context (like htmlspecialchars() for HTML).
  3. If the singleton represents a database connection, the biggest problem is that you'll never be able to establish a second connection within the same script. You may not need multiple connections right now, but that can change in the future. For example, if you decide to store your PHP sessions in the database, the only safe solution is to have an additional database connection just for the session. Now what? You'd have to either copy-and-paste your entire class to create a new singleton, or you'd need a complete rewrite of your database-related code. So this is not future-proof. And testing is indeed a problem as well. This question is far too vague. You should provide a concrete example so that we can comment on this specific case.
  4. You mean a public TLD? Parse the URL and then check if the host ends with a public suffix.
  5. No problem. By the way, never insert user input directly into a query string like you did previously. This allows anybody to manipulate the query and perform an SQL injection attack. For example, any visitor can steal sensitive data like password hashes simply by appending them to the query result. And in the worst case, it's possible to compromise your entire server. Whenever you need to pass dynamic input to a query, use a prepared statement.
  6. The “<your input>” is of course just a placeholder. Create a prepared statement with one parameter for the input price and then bind $_POST['ppprice'] to that parameter.
  7. That's a lot clearer. You can actually do this in MySQL itself: Order the rows by distance from the input and then pick the row with the smallest distance. However, you need a special rule when the input is exactly between two rows (e. g. 225,000). Which row do you pick? The one with the smaller price or the one with the bigger price? I'll assume the former: SELECT * -- select explicit columns! FROM transfer_cost ORDER BY ABS(purchase_price - <your input>) ASC, purchase_price ASC -- in case the input is just between two purchase prices LIMIT 1 ;
  8. You can add unqiue constraints at any time. Both iarp and I gave you the exact query syntax, so all you have to do is fill in your actual column names and run the query. Since you didn't check for unique combinations in the past, you may have garbage data which prevents the constraint from being installed. In that case you need to repair your data first.
  9. mac_gyver meant a composite unique key spanning all three columns, not three individual unique keys. As in: ALTER TABLE yourtable ADD CONSTRAINT UNIQUE (yourfirstcolumn, yoursecondcolumn, yourthirdcolumn);
  10. I don't think anybody can help you based on this description. It's hard to even make sense of the problem when there's no concrete information whatsoever. What kind of “table” are you talking about? Is this an SQL question? What kind of “numbers” do you deal with? Integers? Floats? Something else? You should show a concrete example with concrete data so that we can actually understand what this is about. Also, what do you expect from us? Obviously you don't care about concrete code, so what's the goal of this thread?
  11. PHP 5.3 doesn't support $this in a closure. You need to explicitly import it as a variable: public function render($text, $separator) { $currentObject = $this; $replace = function ($subject) use ($currentObject, $separator) { $subject = $currentObject->render($subject[1], $separator); ... }; } Note that both PHP 5.3 and PHP 5.4 have reached end-of-life.
  12. What's the problem? The code is working just fine. If there's a problem on your machine, you need to tell us exactly what's happening so that we can help you.
  13. Like I already said, you need to call the fetch function repeatedly: $query = mysql_query(...); $children = []; while ($category = mysql_fetch_assoc($query)) { $children[$category['parent_id']] = $category; } Note that the mysql_* functions are horribly outdated and will be removed in the near future. Nowadays, we use modern database interfaces like PDO.
  14. The biggest difference between the command-line interface (CLI) and the web-based interfaces is that the CLI doesn't have access to $_POST, $_GET etc. So if you want to use external values, you need to pass them as command-line arguments. They're then available in $argv. I don't know which interface the above website uses (appearently the CLI). If you want to work with PHP, I strongly recommend you install it locally. There are many tools like XAMPP which are easy to install and already contain a webserver, a database system etc.
  15. Start by fixing the database part: Make sure the query is correct, and then call mysql_fetch_assoc() repeatedly until you've fetched all rows into the $children array. You can check the array with var_dump(). When that's done, you can go on with the recursive function. It will look like this (as pseudo-code): function display_category_level(parent := -1) : if children[parent] : print <ul> for category in children[parent] : print <li> print <h2>category[name]</h2> display_category_level(category[id]) print </li> print </ul>
  16. So how is this “not working”? What's the problem? Taking a wild guess: You only fetch the first row. To get all rows, you need to call mysql_fetch_assoc() repeatedly. The loop logic is flawed: When a category has no more children, the loop is immediately stopped. The check within the loop which should close the list and update the parent isn't reached. I strongly recommend that you use recursion instead of the current iterative approach. It will make the code much easier to understand.
  17. No, this doesn't have anything to do with the maximum upload size, it's a memory problem. If at all, you'd decrease the maximum filesize so that image manipulation takes less memory. Increasing it to 128M would be counter-productive, because then you definitely exceed the memory limit and fill up your hard drive.
  18. No, this doesn't make any sense. The settype() function doesn't actually “set a type”. PHP is not a statically typed language like Java, it doesn't have fixed variable types. What this function does is convert the value of the variable, but since that value already is an integer in your case, the function has no effect whatsoever. Checking for $test == true is the same as checking for $test, so there's no good reason for the extra “== true”. Last but not least, this approach is really complicated and confusing. If I didn't know the context, I probably wouldn't even understand what you're trying to do there. So you shouldn't do this, not even for learning. Make your code explicit and easy to understand.
  19. Yes, the method is called repeatedly to handle nested expressions. You can use a closure as the callback function. It has access to variables in the scope of its definition: <?php class TextGenerator { const REGEXP = '/\{(((?>[^{}]+)|(?R))*)\}/'; public function render($text, $separator) { $replace = function ($subject) use ($separator) { $subject = $this->render($subject[1], $separator); $parts = explode($separator, $subject); return trim($parts[array_rand($parts)]); }; return preg_replace_callback( self::REGEXP, $replace, $text ); } } $textGenerator = new TextGenerator(); $separator = '/'; echo $textGenerator->render('We sell {furry {cats/kittens}/adorable dogs}.', $separator); This is actually a cleaner solution in general, because you don't need a pseudo-public replace() method.
  20. If that already confused you, how about this:? $str_1 = "150e3"; $str_2 = " 150000"; var_dump($str_1 == $str_2); // true So PHP not only converts operators with different types. It also converts operators with the same type into another type when it has the chance to (in this case, it regards the strings as numbers in exponential notation). To get around this madness, be explicit and don't rely on PHP doing the right thing. It won't. If you want to compare strings, use strcmp() or the === operator as suggested by Ch0cu3r. Of course you may take advantage of some automatic conversions (that's what PHP is for, right?), but then you should really understand what's going on internally.
  21. Your loop doesn't get you anywhere, because you just keep overwriting the same variable. Also, never write PHP variables directly into JavaScript contexts. This can lead to anything from syntax errors to full-blown cross-site scripting vulnerabilities. If you want the timer to keep running, you need to store the time when it was started. This can be done server-side or client-side, depending on your requirements. If the timer is important and must not be reset by the user, you need an additional timestamp column which you set as soon as you retrieve the record for the first time. If the timer is just-for-fun, you may use a cookie instead. The table for the server-side solution would look something like this: - record_id INT - expiry_minutes INT UNSIGNED - expiry_start DATETIME (initially NULL) - ... Before you retrieve the records, you first initialize the expiry starts which haven't been initialized yet. Then you can calculate the remaining time for each record: db("update records set expiry_start = now() where record_owner = <current_user> and expiry_start is NULL") records := db("select records where record_owner = <current_user>") foreach record in records: remaining_time := record.expiry_start + record.expiry_minutes - now() ... There are two ways for safely passing the timer values to JavaScript: You first send all records as plain HTML. Then you make an Ajax request to retrieve the timer values and start the timers. In your PHP code, you create a JSON object while you retrieve the rows and embed that object into a hidden HTML element. Then your JavaScript code can parse the data and create the timers. Pick whatever you like best. The latter is a bit easier to implement, because you don't need any Ajax requests.
  22. Hi, prepared statements are the primary mechanism for making sure that input data cannot change the structure of a query. If used correctly, they reliably prevent SQL injection attacks as well as accidental syntax conflicts (like when you try to insert a single quote into a single-quoted string literal).Note that some database interfaces like PDO use “fake” prepared statements which do not provide this level of robustness. By default, calling PDO::prepare() and PDOStatement::execute() merely auto-escapes the input, inserts it into the query string and then sends the whole string to the database system. This is much less secure and has the exact same issues as manual escaping (see below). An actual prepared statement always consists of two separate steps: You send a query template to the database system, and then you pass specific data to this template and execute it. To enable this two-step process in PDO, you need to explicitly turn PDO::ATTR_EMULATE_PREPARES off. As a secondary line of defense, you should validate the input data whenever possible. For example, use ctype_digit() to make sure that a variable only contains decimal digits. If it doesn't, reject the input and generate an appropriate error message. Do not try to “fix” the input with the FILTER_SANITIZE_* constants or through type casting. This is extremely confusing and can cause severe problems. For example, let's say I ask you to delete the row with the ID “12a3”, which is clearly an incorrect request. It would be insane if you picked a different ID (like “12”) and deleted that row instead, because I never asked you to. Type casting can also lead to truncation bugs. Escaping is a less secure alternative to prepared statements. They cannot be used together, because all the escape characters would literally be inserted into your database. The input doesn't run through any SQL parser (that's the whole point of prepared statements). There are many problems associated with escaping, so it should generally we avoided: Even the best developers forget to escape a value from time to time, or maybe they think it's safe when it isn't. This immediately leads to a potential SQL injection vulnerability. Escaping isn't trivial. There are dozens of incorrect functions, and even if you've picked the right one, you may still screw up (e. g. mysql_real_escape_string() is useless without surrounding quotes). Since escaping happens in the application rather than in the database system itself, there's always a certain risk that a seemingly safe query is misinterpreted and turned into an SQL injection by the database system. The last problem is particularly nasty, because it can happen even when you think you've done everything correctly. For example: If the application uses backslash-escaping, it will produce queries like SELECT username FROM users WHERE id = '123\'UNION SELECT password FROM users-- ' From the application's perspective, this is perfectly safe, because it has the following structure: SELECT username FROM users WHERE id = <some string> However, the database system may have disabled backslash-escaping, so it interprets the query like this: SELECT username FROM users WHERE id = <some string> UNION SELECT password FROM users That's a full-blown SQL injection which yields all password hashes stored in the database. The same can happen if the application doesn't use the same character encoding as the database. If you do need to use escaping (e. g. on legacy systems), you have to be super-careful: Escape all values, even if you think they're safe. Only use mysql_real_escape_string(). Forget about addslashes() or anything like that. The escaped string must be enclosed in quotes. Otherwise escaping is useless. If you need to change the character encoding at runtime, use mysql_set_charset(). Do not run a SET NAMES query, because this can lead to an encoding mismatch between the database system and the application. Long story short: Prepared statements are by far the most robust solution as long as you make sure they're not “emulated” in the application.
  23. The regex is perfectly fine, but you're not using the class correctly. What this does is look for substrings of the kind {<choice1>|<choice2>|<choice3>|...|<choicen>} and randomly replace them with one of the substrings <choice1>, <choice2>, <choice3>, ..., <choicen>. For example, Have a look at our {fabulous|fantastic|awesome} pet shop. could become “Have a look at our fantastic pet shop.” or “Have a look at our awesome pet shop”. Nested patterns are also supported: We sell {furry {cats|kittens}|adorable dogs}. So it's basically a simple text generator. You use the class by calling the render() method with an appropriate input. Do not call replace(), that's just an internal method. <?php class TextGenerator { const REGEXP = '/\{(((?>[^{}]+)|(?R))*)\}/'; public function render($text) { return preg_replace_callback( self::REGEXP, [$this, 'replace'], $text ); } public function replace($text) { $text = $this->render($text[1]); $parts = explode('|', $text); return trim($parts[array_rand($parts)]); } } $textGenerator = new TextGenerator(); echo $textGenerator->render('We sell {furry {cats|kittens}|adorable dogs}.');
  24. You only need a single query to get all information. The one I posted contains a complete matrix of all players, all tanks and whether a particular player has a particular tank. To make life easier, you may want to put the result into a two-dimensional array before doing the output, as suggested by mac_gyver. $tankPlayersQuery = $databaseConnection->query(' SELECT tanks.tank_id, tanks.tank_name, players.player_id, players.username, player_tanks.player_id IS NOT NULL AS combination_exists FROM players CROSS JOIN tanks LEFT JOIN player_tanks ON players.player_id = player_tanks.player_id AND tanks.tank_id = player_tanks.tank_id ORDER BY tanks.tank_name ASC, players.username ASC '); $tankPlayersResult = $tankPlayersQuery->fetchAll(); $tankPlayers = []; foreach ($tankPlayersResult as $row) { $tankPlayers[$row['tank_name']][$row['username']] = ($row['combination_exists'] == 1); } To get all players for the table heading, you just have to pick a row from the two-dimensional array and get its keys: $firstTank = reset($tankPlayers); $players = array_keys($firstTank); var_dump($players);
  25. You can use debug_backtrace() to get the original file which included your debug script. It's the last entry in the list.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.