Jump to content
Larry Ullman's Book Forums

All Activity

This stream auto-updates     

  1. Yesterday
  2. Last week
  3. Hi Larry, Thank you very much for your answer. What you explained makes perfect sense so I will exclude the duplicate login for the project. Regards.
  4. For starters I definitely wouldn't put this into the users table. That table represents an entity: the user. What you're describing is representing activity, so I'd create a logins table for that. As for the goal itself, as I'm sure Netflix can attest, this is tricky and may not be worth the effort. You can't assume people will log out, as you noted. But that also includes situations like I start using the site on one device but then go to switch devices. I definitely access some sites on multiple devices in a single day. In any case, the best thing I can think of would be to rely upon sessions here. Store the session ID in the database, along with the user ID. Sessions will automatically expire after inactivity, based upon your site/server settings. When someone logs in, you could check if there's an active session already. But I wouldn't bother, personally. You'll have to create a lot of work to hopefully catch a few cheaters while occasionally annoying legitimate users. I'd rather put my effort into making a product so great people would gladly pay for it.
  5. Hi Larry, I want to manage logins to disallow duplicate logins so that one subscriber can't use another subscriber's login credentials to log in simultaneously. I was thinking of adding a "logged_in" ENUM column to the user table with values "Yes" and "No". The value is set to "Yes" when the user logs in and to "No" when the user logs out. But if the user just closes the browser window without logging out via the website, that would create an issue when the user tries to log in again. Your thoughts on this will be much appreciated. Regards.
  6. Earlier
  7. Thank you very much for your answer Larry. Of course it makes perfect sense to me now!
  8. That's an excellent question! Depending upon what it means to be an "admin" user, I'd be inclined to not allow admin users to reset their password at all. If a password is forgotten, the admin should personally contact the site--who presumably knows the admin--who would manually help with the reset. Such an arrangement, while inconvenient, would prevent a hack attempt.
  9. Hi Larry, Thank you very much for your response. I changed the innodb_log_file_size and innodb_log_file_size in the my.ini text file as recommended in the StackOverflow article without any success. Changing the storage engine from InnoDB to MyISAM seems to have solve the issue so should I just continue with MyISAM? If I run into issues with MyISAm I will have to switch the columns and the rows as you suggested. Regards.
  10. Hi Larry, Thank you for your guidance. The query from the code above calls all the users, languages and time zones from their respective tables so no wonder the script didn't execute! The correct query is: $q = "SELECT a.user_id, u.type, u.email, LEFT(u.first_name,1) AS icon, CONCAT(u.first_name, ' ', u.last_name) AS name, u.lang_id, u.timezone_id FROM access_tokens AS a INNER JOIN users AS u ON u.id=u.id WHERE a.token=? AND a.user_id=u.id AND a.date_expires>NOW()"; The script now executes and stores the correct sessions. Just one last question if I may: Should I generate a session id for an admin user within the reset.php script or let the admin user first reset his or her password via the link and then sign out and sign in again through the signin.php page which will generate the admin session? My main concern is security.
  11. Hi, Thanks for the editions and giving us chance and ability to enhance our skills in php platform. We are waiting for the newer addition and also I am doing coding for my own blog website. https://www.technocratshorizons.com/mobile-app-development/
  12. It looks like this is most commonly caused by InnoDB settings: https://stackoverflow.com/questions/22637733/mysql-error-code-1118-row-size-too-large-8126-changing-some-columns-to-te/33655143 If you'd like to keep the current approach and aren't going to add like double the current number of columns, you can try that. If this is going to continue to balloon in size, you'll need to dramatically rethink how translated text is stored. An option would be to switch the rows and columns. You won't have the row size issue anymore but you'll need to select the one column for every row and then use that query to populate a PHP array, which is laborious. Alternatively you could store all the translations in one string, like in JSON format. Retrieval and usage shouldn't be too bad but updating the values will be effortful. There's a number of ways you could approach this but those are the first two that come to mind. Everything has its tradeoffs!
  13. So I believe the page gives that result if that "SELECT a.user_id, u.email, LEFT(u.first_name,1) AS icon, ..." query doesn't return exactly one row. There wasn't anything obviously amiss there upon first inspection. I would run the query manually using the mysql client to see why it's not returning a row. (You'll need to insert the token value into the query, of course.) Try removing various conditionals to see which is the problem.
  14. Hi Larry, I have incorporated the language part of the forum project into my e-commerce site. I have however ran into issues with MySQL/MariaDB regarding the number of word columns representing the translatable words for the site (over 250 so far). I get the following database error: "Warning: #139 Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline." Do you have any suggestions on a different approach maybe as having so many columns in a database table is probably not a good idea? Thank you.
  15. Hi Larry, Thank you very much for your response. I updated the query and it doesn't give the "ambiguous" error anymore, but it now gives the following user reset error: "Either the provided token does not match that on file or your time has expired. Please resubmit the "Forgot your password?" form." The script does insert a new token and the correct date/time into the "access_tokens" table. I also checked the query again and couldn't find any errors. My script is included below. Your thoughts would be much appreciated. Thank you. <?php // Require the configuration before any PHP code as the configuration controls error reporting: require('includes/config.inc.php'); // The config file also starts the session. // Redirect invalid user: if (isset($_SESSION['user_id'])) { $url = 'index.php'; // Define the URL. header("Location: $url"); exit(); // Quit the script. } // Require the database connection: require(MYSQL); // Include the page title: $page_title = $words['reset_page_title_1']; // Include the HTML header file: include('templates/header.html'); // For storing reset error only: $reset_error = ''; // For storing password errors: $pass_errors = array(); if (isset($_GET['t']) && (strlen($_GET['t']) === 64) ) { // First access $token = $_GET['t']; // Fetch the user ID: $q = "SELECT a.user_id, u.email, LEFT(u.first_name,1) AS icon, CONCAT(u.first_name, ' ', u.last_name) AS name, l.lang, t.timezone FROM access_tokens AS a INNER JOIN users AS u ON u.id=u.id INNER JOIN languages AS l ON l.id=l.id INNER JOIN timezones AS t ON t.id=t.id WHERE token=? AND a.date_expires>NOW()"; $stmt = mysqli_prepare($dbc, $q); mysqli_stmt_bind_param($stmt, 's', $token); mysqli_stmt_execute($stmt); mysqli_stmt_store_result($stmt); if (mysqli_stmt_num_rows($stmt) === 1) { mysqli_stmt_bind_result($stmt, $user_id, $email, $icon, $name, $lang_id, $timezone_id); mysqli_stmt_fetch($stmt); // Create a new session ID: session_regenerate_id(true); $_SESSION['user_id'] = $user_id; // Store the data in a session: //$_SESSION['user_id'] = $user_id; $_SESSION['email'] = $email; $_SESSION['icon'] = $icon; $_SESSION['name'] = $name; $_SESSION['lid'] = $lang_id; $_SESSION['timezone'] = $timezone_id; // Clear the token: $q = 'DELETE FROM access_tokens WHERE token=?'; $stmt = mysqli_prepare($dbc, $q); mysqli_stmt_bind_param($stmt, 's', $token); mysqli_stmt_execute($stmt); } else { $reset_error = '<div class="reset my-5"> <div class="reset-header text-center"> <i class="fas fa-lock fa-4x"></i> <h2 class="display-5 my-2 font-weight-normal">' . $words['reset_message_1'] . '</h2> <p class="my-3 font-weight-normal text-center">' . $words['reset_message_2'] . '</p> </div> </div>'; } mysqli_stmt_close($stmt); } else { // No token! $reset_error = '<div class="reset my-5"> <div class="reset-header text-center"> <i class="fas fa-lock fa-4x"></i> <h2 class="display-5 my-2 font-weight-normal">' . $words['reset_error_1'] . '</h2> <p class="my-3 font-weight-normal text-center">' . $words['reset_error_2'] . '</p> </div> </div>'; } // If it's a POST request, handle the form submission: if (($_SERVER['REQUEST_METHOD'] === 'POST') && isset($_SESSION['user_id'])) { // Okay to change password: $reset_error = ''; // Check for a password and match against the confirmed password: if (preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{12,})^/', $_POST['pass1']) ) { if ($_POST['pass1'] == $_POST['pass2']) { $p = $_POST['pass1']; } else { $pass_errors['pass2'] = $words['reset_validation_1']; } } else { $pass_errors['pass1'] = $words['reset_validation_2']; } if (empty($pass_errors)) { // If everything's OK. // Define the query: $q = 'UPDATE users SET pass=? WHERE id=? LIMIT 1'; $stmt = mysqli_prepare($dbc, $q); mysqli_stmt_bind_param($stmt, 'si', $pass, $_SESSION['user_id']); $pass = password_hash($p, PASSWORD_BCRYPT); mysqli_stmt_execute($stmt); if (mysqli_stmt_affected_rows($stmt) === 1) { // Send a confirmation email: $email = ($_SESSION['email']); $body = $words['reset_email_1']; $body = wordwrap ($body,70); mail($email, $words['reset_email_2'], $body, 'FROM: ' . SEND_EMAIL); // Let the user know the password has been changed: echo '<div class="reset my-5"> <div class="reset-header text-center"> <i class="fas fa-lock fa-4x"></i> <h2 class="display-5 my-2 font-weight-normal">' . $words['reset_message_3'] . '</h2> <p class="my-3 font-weight-normal text-center">' . $words['reset_message_4'] . '</p> </div> </div>'; include('templates/footer.html'); // Include the HTML footer file. exit(); } else { // If it did not run OK. trigger_error('<div class="reset my-5"> <div class="reset-header text-center"> <i class="fas fa-lock fa-4x"></i> <h2 class="display-5 my-2 font-weight-normal">' . $words['reset_error_3'] . '</h2> <p class="my-3 font-weight-normal text-center">' . $words['reset_error_4'] . '</p> </div> </div>'); } mysqli_stmt_close($stmt); } // End of empty($pass_errors) IF. } elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { $reset_error = '<div class="reset my-5"> <div class="reset-header text-center"> <i class="fas fa-lock fa-4x"></i> <h2 class="display-5 my-2 font-weight-normal">' . $words['reset_error_5'] . '</h2> <p class="my-3 font-weight-normal text-center">' . $words['reset_error_6'] . '</p> </div> </div>'; } // End of the form submission conditional. // If it's safe to change the password, show the form: if (empty($reset_error)) { // Requires the form functions script, which defines create_form_input(): require_once('includes/form_functions.inc.php'); echo '<form class="reset my-5" action="reset.php" method="post" accept-charset="utf-8"> <div class="reset-header text-center"> <i class="fas fa-lock fa-4x"></i> <h2 class="display-5 my-2 font-weight-normal">' . $words['reset_form_1'] . '</h2> <p class="my-3 font-weight-normal text-center">' . $words['reset_form_2'] . '</p> </div>'; create_form_input('pass1', 'password', '', $pass_errors, array('placeholder'=>$words['reset_form_3'])); echo '<small class="form-text text-muted">' . $words['reset_form_4'] . '</small>'; create_form_input('pass2', 'password', '', $pass_errors, array('placeholder'=>$words['reset_form_5'])); echo '<input type="submit" name="submit_button" value="' . $words['reset_form_6'] . '" id="submit_button" class="btn btn-lg btn-block btn-custom" /> </form>'; } else { echo '<div class="reset my-5"> <div class="reset-header text-center"> <i class="fas fa-lock fa-4x"></i> <h2 class="display-5 my-2 font-weight-normal">' . $reset_error . '</h2> <p class="my-3 font-weight-normal text-center">' . $reset_error . '</p> </div> </div>'; } // Include the HTML footer file. include('templates/footer.html'); ?>
  16. So you need to clarify which date_expires you're referring to by prefacing "date_expires" with the table name or alias. As you're probably referring to the access_tokens table, which has been aliased to "a", you'd change the conditional to "AND a.date_expires > NOW()". What you tried was close but a query only has one "FROM" clause and you added a second one as part of the "WHERE" conditionals.
  17. Hi Larry, I changed the database query from the original in your reset_password.php script to the below query in order to get the values to assign to the user's sessions when the URL signs the user in. I get the following error (Column 'date_expires' in where clause is ambiguous) because the users table also has a 'date_expires' column. What alias should I use on 'date_expires'? I tried (a.date_expires>NOW() FROM access_tokens AS a) but it obviously didn't work and couldn't find anything useful on the net. Any suggestions would be much appreciated. $q = "SELECT a.user_id, u.email, LEFT(u.first_name,1) AS icon, CONCAT(u.first_name, ' ', u.last_name) AS name, l.lang, t.timezone FROM access_tokens AS a INNER JOIN users AS u ON u.id=u.id INNER JOIN languages AS l ON l.id=l.id INNER JOIN timezones AS t ON t.id=t.id WHERE token=? AND date_expires>NOW()";
  18. Hi Larry, Thank you for your response. I changed the $_POST to assign the value for each form field with: value="' . $row[0] . '", value="' . $row[1] . '" etc. All the input form fields display the correct data from the database as previously, except for the select fields. The select fields also now also gives the following error: (An error occurred in script 'C:\xampp\htdocs\...' on line 246: Trying to access array offset on value of type null). When I assign the select value to an input field, the correct data is displayed in the field. I couldn't find anything helpful on Stack Overflow.
  19. Hi Larry, Please accept my apology for wasting your time. I got the query for checking for the unique email wrong as I left out the "!" when checking the email against the user_id. I fixed that and the query and script executes perfectly now. Sorry again, and thanks for your prompt response and excellent forum!
  20. Hi Larry, I opted for option A and it works perfectly. Thank you for the great and continued support for your books through this forum! Regards.
  21. The code you have looks okay to me. If it's not working, I'd start by looking at the HTML source of the output to see if there's something useful there. Also, should you be using POST or GET?
  22. Ah, good question! There are two options: A. Use the current code but before the current session is destroyed, copy the lang ID to a new variable and then after the current session and cookie are destroyed, start a new session and store the lang ID in that using the variable. or B. Don't clear and destroy the session in this script, only remove those session elements that represent "being logged in".
  23. Hey! If you're talking about Script 10.3, it doesn't require that the email be updated. It uses the form values to "update" the email address in the database, but the form value could very well be the same as the current value.
  24. Hi Larry, I want to assign the value from $_POST['lang'] = $row[3]; to the below select form, but can't get it to work. Any recommendations? Thank you! // Language drop down menu: echo '<div class="form-group'; if (array_key_exists('lang', $profile_errors)) echo ' has-error'; echo '"><select name="lang" id="lang" class="form-control"> <option>' . $words['profile_form_6'] . '</option>'; // Retrieve all the languages and add to the pull-down menu: $q = "SELECT id, lang FROM languages WHERE status='Active' ORDER BY lang ASC"; $r = mysqli_query($dbc, $q); if (mysqli_num_rows($r) > 0) { while ($row = mysqli_fetch_array($r, MYSQLI_NUM)) { echo "<option value=\"$row[0]\""; // Check for stickyness: if (isset($_POST['lang']) && ($_POST['lang'] == $row[0]) ) echo ' selected="selected"'; echo ">$row[1]</option>\n"; } } mysqli_free_result($r); echo '</select>'; if (array_key_exists('lang', $profile_errors)) echo '<span class="help-block">' . $profile_errors['lang'] . '</span>'; echo '</div>';
  1. Load more activity
×
×
  • Create New...