Jump to content

Jacques1

Members
  • Posts

    4,207
  • Joined

  • Last visited

  • Days Won

    209

Everything posted by Jacques1

  1. Making the IP address unique is a bad idea, because this will lock out many legitimate users. In fact, the IP address is most definitely shared among many people, be it due to an Internet connection with multiple users, a proxy server, a VPN, Tor etc. Once you've blocked a couple of big services, large parts of the Internet population will be unable to visit your site. At the same time, an actual attacker can easily obtain a new address. If you want to limit abuse, install reCAPCHA. It's much more effective against attackers and much less harmful for legitimate users. The recommend way to access a MySQL database with PHP is via PDO. It should already be installed on the server: <?php // database credentials const DB_HOST = 'localhost'; const DB_USER = '???'; const DB_PASSWORD = '???'; const DB_NAME = '???'; const DB_CHARSET = 'UTF8'; // MySQL error codes const MYSQL_ER_DUP_ENTRY = 1062; // establish a database connection $dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset='.DB_CHARSET; $database_connection = new PDO($dsn, DB_USER, DB_PASSWORD, [ PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); // test connection var_dump( $database_connection->query('select * from contest_submissions')->fetchAll() );
  2. You already have the table definition. Did you create that table?
  3. That's why we have this forum: To help people solve problems which exceed their current knowledge. While you were busy writing your cronjob hack, I've written the script. It took me ~10 minutes, 2 queries (CREATE and INSERT) and ~50 lines of plain PHP code. That's not exactly rocket science. And unlike your hack, it actually solves the problem. But if you prefer to run a cronjob every 5 minutes, go ahead.
  4. If you want to make use of this forum, it's a good idea to actually listen to the advice you get. Most of us are professional developers, so we know a bit about implementing features like this. When requinix tells you to use an SQL database, he means it. That code you've “found somewhere” is nonsense. You can spend the rest of your time trying to fix it, but you'll still end up with up cheaters sabotaging your contest. This leaves you with two options: You accept that the contest is just a fun project and let users post whatever they want. Or you take this seriously and set it up in a way that it actually works. Even the cheapest hoster today has MySQL, so I'm sure you already have a database and probably even phpmyadmin (which is a graphical administration tool). Here's the table definition: CREATE TABLE contest_submissions ( contest_submission_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, btc_address VARCHAR(35) NOT NULL UNIQUE, username VARCHAR(10) NOT NULL, ip_address VARCHAR(15) NOT NULL ); People who try to post a large number of requests can be stopped with CAPTCHAs like reCAPTCHA.
  5. You also don't need random.org to pick a random visitor. PHP itself provides several random number generators from toy-grade to cryptography-grade.
  6. It's example code, and I thought it's obvious how to insert different or additional parameters. <form method="post" action="?{{ {'id': get.id, 'p': get.p}|url_encode }}"> Alternatively, you could just copy the entire URL query (i. e. $_SERVER['QUERY_STRING']), but then you may copy garbage data as well. ?
  7. Add the missing question mark. <form method="post" action="?{{ {'id': get.id}|url_encode }}"> ^
  8. There's no need for special code for the dropdown. Simply pass all membership categories to the template: 'membership_categories' => $pdo->query('SELECT membership_category_id, membership_category FROM membership_category')->fetchAll() Building the dropdown menu can be done in the template. To preselect an option, check the defaults array: {% if membership_data.membership_category_id is defined and category.membership_category_id == membership_data.membership_category_id %}selected{% endif %} Nothing terribly important. You should avoid using SCRIPT_FILENAME for form actions, because it's unnecessary and assumes that the public URL matches the physical filename (which is not true when you start rewriting URLs). Relative URLs like in #37 are much more convenient and robust. For example, “?id=12” is automatically resolved to the right path. The validation which happens in the included script and “magically” updates the $errors array is confusing. A function would be better.
  9. <?php if ($_SERVER['REQUEST_METHOD'] == 'POST') // update or add record { if (isset($_GET['id'])) { // @TODO update record } else { // @TODO add new record } $membership_data = $_POST; } elseif (isset($_GET['id'])) // initial form for editing record { $membership_data = load_membership_data($_GET['id']); } else // initial form for adding record { $membership_data = []; } // @TODO pass $membership_data to template <form method="post" action="{{ {'id': get.id}|url_encode }}"> <input type="text" name="membership_type_description" value="{{ membership_data.membership_type_description ?? '' }}"> ... </form> Yes (or a simple link).
  10. @benanamen: I think I understand now where the problem is and why we've been talking past each other: You seem to already load the initial form with a POST request, because there are no URL parameters for the ID (only $_POST['id']). That would explain why you need this strange if-empty-then-load-from-database logic for each individual field: You need it to prefill the initial form. Unfortunaly, this logic doesn't work in subsequent requests, because as kicken and I already said, you'll override fields which the user has left empty. To fix this, put the ID into a URL parameter. Then you can actually distinguish between the different cases like in #33: when in edit mode with a GET request, load values from database when in edit mode with a POST request, take values from POST parameters when in add mode, use empty values
  11. Your output doesn't make any sense at all. The XML declaration is fudged up, the tags are wrong (since they've been changed to all-lowercase), and the output shouldn't even be formatted. Either you haven't provided your real code, or there's something which messes with the XML output. This is the raw output of $xmlHandler->SaveXml() after enabling formatted output: <?xml version="1.0" encoding="UTF-8"?> <RootNode> <NodeLevel1>Text1 - This node one has text</NodeLevel1> <NodeLevel2>Text2 - Next node Level3 level is not gonna have text<NodeLevel2_1>Text2_1 - This node will be a child of Level2, everything fine</NodeLevel2_1></NodeLevel2> <NodeLevel3/> <NodeLevel4>Text4 - This node should be on same level like 3, 2 & 1, but instead it's a child of Level 3 (?!?!?!?!)</NodeLevel4> </RootNode> If you get something else, save the return value of $xmlHandler->SaveXml() in a file on your server and inspect that file.
  12. The function doesn't have access to any $row variable, you need an extra parameter for this. Actually, I wonder if the logic even make sense. Right now, posting an empty field resets the field to the value from the database, which is definitely not what I expect as a user. If an empty value isn't permitted, the application should say so instead of silently altering my input. So I'd rather go with three strictly separated cases: When the user has posted data, all field values are taken from $_POST (with error messages when needed). A database query isn't necessary. If the user edits the entity for the first time, all values are taken from the database. If the user adds a new entity, all fields are empty.
  13. First off, letting users upload arbitrary files is suicidal. It's an open invitation to attack your server and other visitors. You can also get into legal trouble when your server starts spreading malware, copyrighted material or other illegal files. Don't do this, not even for testing, not even for a short amount of time. The “file manager” also cannot be taken seriously. It isn't even able to reliably distinguish between the different files, because the numbering scheme changes whenever the directory content changes. If I delete the “second file”, I have no idea if that's still the same file I saw when the page was initially loaded. It could be anything now. If you just want direct access to your filesystem, use SCP/SFTP. Otherwise you need to know what you're doing. A file upload must involve strict validation and a database for properly managing files.
  14. PHP creates an array on the fly when you write elements into an undefined variable, yes. But it's a lot more clear both for humans and tools if you explicitly define the array first. For example, PhpStorm cannot infer the type of $a in the following code, and asking for the definiton only gets me to the first array acess in line 4: <?php if (true) $a['x'] = 2; else $a['x'] = 3; Adding an explicit array definition fixes both problems: <?php $a = []; if (true) $a['x'] = 2; else $a['x'] = 3; Needless to say, most (if not all) other languages actually require the initial definition.
  15. Yes, which is not a problem for an isolated "offline" directory.
  16. Many things are possible, but I still have no idea why you need or want this odd approach for your API. In case my suggestion wasn't clear: You put your files into a directory outside of the document root, then your API serves the contents, ideally with X-Sendfile. Now the files cannot be accessed directly, because they don't exist in the document root, but they can be accessed through your API. This also allows you to completely hide any path information. You can use numerical file IDs or just the filename or any identifier you want. Now you're talking about a different task. If you want to list the directory content with an iterator, you indeed need read access. Previously, you asked about writing files.
  17. If you don't want to make a file publicly accessible, don't put it into the document root at all. There's no reason why the user should get anything other than a 404 code. This 403 hack is nonsensical, risky and complicated (you'd have to run the webserver and PHP under two different accounts or mess with the webserver configuration). Creating files in a directory requires execute + write permissions (numerical: 3). So you don't need anything more than 0730. When you need to create files dynamically, this should happen outside of the document root in a separate directory to prevent code execution and manipulations of the application itself.
  18. When the owner of a file is root:root and the permissions are set to 0640, then by definition nobody other than root can read the file. This is how Unix permissions work and have always worked. In general, scripts should never be owned or writable by the webserver, because this makes them vulnerable to malware infections. They should be read-only. Set the owner to root, the group to www-data and the permissions to 0740. 5 means read + execute. You need write + execute, i. e. 3. But don't allow the webserver to create files within the main application directory, because this again can lead to the injection of malicious scripts.
  19. My point is that you must not store your documents in the same directory which contains your PHP scripts, .htaccess files and other internal data, because those are none of the user's business. You have to create an extra folder (let's call it “documents”) and display the content of that folder: <?php const DOCUMENT_DIRECTORY = __DIR__.'/documents'; // __DIR__ is the path of the current directory // iterate over documents in the document directory foreach (glob(DOCUMENT_DIRECTORY.'/*') as $document) { var_dump($document); } This is a lot safer, because the document directory by definition only contains public files (and hidden files like .htaccess are automatically skipped). This also means you can get rid of the blacklisting stuff. Besides that, I'm not sure what you're asking. Do you want to be able to click on a subdirectory and get its content? This is slightly more difficult. You have to make the webserver rewrite all URLs pointing to directories (but not files) within the document directory so that the requests are instead sent to your script (together with the original URL). Within the script, you verify the received path and then display the content. Which webserver are you using? Apache? A word of advice: Since you're new to PHP and have chosen a fairly critical project, I strongly recommend you don't put this online yet. Run it on your PC, use it for learning, but don't expose it to the Internet.
  20. What exactly is the problem? As far as I can tell, the function definition is just hard-coded text, so all you have to do is put that text into a string (preferrably with a nowdoc): $cdata = $xml->createCDATASection(<<<'INIT_DEF' function init() print "inside epg" m.content = createObject("RoSGNode","ContentNode") m.top.setFocus(true) dateNow = CreateObject("roDateTime") dateNow = dateNow.asSeconds() - 2000 addChannel("ABC") addItem("ABC Show ", dateNow) m.top.content = m.content m.top.translation = [50, 300] m.top.numRows = 5 m.top.duration = 10800 m.top.nowNextMode = false m.top.infoGridGap = 0 m.top.channelInfoColumnLabel = "Hello" end function INIT_DEF );
  21. Yes. The submit button must be "sendmepass", the text field must be "affiliatername" (which is somewhat logical, I think).
  22. So what is your question? And what on earth are you doing there? Why would you show all files of the internal application directory (minus a few blacklisted extensions) for everybody to see? Do you not understand how risky this is? If you want to serve a collection of files, you put them into a separate directory, not right between your PHP scripts.
  23. How would that solve any problem? A function call in the same process doesn't make the process shorter in any way. kipps' idea is to solve the timeout problem by splitting the long-running process into multiple independent short-lived processes. But as I already said in #3, timeout problems are solved by either optimizing the procedure (if possible) or increasing the time limit. There's no need for any hacks.
  24. When you get the default values for your membership fields, you repeat the exact same pair of if statements over and over again with the only difference being the field name. This screams for a loop: $membership_fields = [ 'membership_category_id', 'membership_type', 'membership_type_description', 'is_promo', 'is_active', ]; $membership_data = []; foreach ($membership_fields as $membership_field) { if (!empty($_POST[$membership_field])) { $membership_data[$membership_field] = $_POST[$membership_field]; } elseif (!empty($row[$membership_field])) { $membership_data[$membership_field] = $row[$membership_field]; } else { $membership_data[$membership_field] = ''; } } This cuts the code volumne in half and allows you to easily add field without having to repeat the if statements yet again. And why not just leave the exception alone?
  25. With pre-rendering I mean your $options array at the bottom of the script (which you adopted from reply #5). This is unnecessary and blurs the line between business logic and presentation. See #6 for an alternative. Besides that, I don't see any fundamental problems. A couple of suggestions: You can make the code a lot shorter if you replace all the if(!empty($row...)) ... elseif (!empty($_POST...)) checks with a loop that goes through this procedure once for every field. I would replace the {{ is_promo ? 'checked="checked"' : '' }} with a simple {% if is_promo %}checked{% endif %}. The checked="checked" syntax is an obsolete XHTMLism. You should get rid of the try-catch statement.
×
×
  • 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.