Jump to content
Larry Ullman's Book Forums

Jacques

Members
  • Posts

    70
  • Joined

  • Last visited

Everything posted by Jacques

  1. Hi Larry, Thank you very much for taking the time to explain the implementation details. Hopefully I can get my head around it! Kind regards.
  2. Thank you for your response Larry. If you could perhaps offer some guidance in terms of how you would approach such a subscription model, it would be much appreciated. Kind regards.
  3. Hi Larry, I want to offer different subscription plans on my virtual products site (free, basic, standard and premium) that would limit subscribers to a number of views. Should I use the virtual subscription model (Part 2) and adapt it, or use the shopping cart model (Part 3)? Regards.
  4. 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.
  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. Thank you very much for your answer Larry. Of course it makes perfect sense to me now!
  7. 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.
  8. 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.
  9. 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.
  10. 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'); ?>
  11. 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()";
  12. 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.
  13. 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!
  14. 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.
  15. 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>';
  16. Hi Larry, My logout message "You are now logged out." from my logout.php script (below) reverts back to the default language (English) when the user logs out. How do I get the $_SESSION['lid'] = $row['lang_id'] to remain valid until just after the user logged out so that the logout message displays in the user's selected language? Thank you. <?php /* This script: - is the sign out page for the site. - calls the configuration script. - redirects invalid users. - opens the database connection. - destroys the variables, session and cookie. */ // 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. } // Destroy the session: $_SESSION = array(); // Destroy the variables. session_destroy(); // Destroy the session itself. setcookie (session_name(), '', time()-300); // Destroy the cookie. // Require the database connection: require(MYSQL); // Include the page title: $page_title = $words['signout_page_title_1']; // Include the HTML header file: include('templates/header.html'); // Print a message: echo '<h2 class="display-5 my-2 font-weight-normal">' . $words['log_out_message'] . '</h2>'; // Include the HTML footer file: include('templates/footer.html'); ?>
  17. Hi Larry, I want to update a user's data where the unique email will either be updated or not. Using the script as it stands, the email has to be updated for the script to execute successfully. Do you have any suggestions on how to approach this because I can't figure out for the life of me if it would be done with validation or a database query or a combination of both? Thank you.
  18. Hi Larry, Thank you very much for your response. I have checked both the videos.php and view_video.php scripts again and also compared them to the original pdfs.php and view_pdf.php scripts, which execute perfectly. Apart from the variable and Content-type changed from "pdf" to "mp4" and "application/pdf" to "video/mp4" in the video scripts, the pdf and video scripts are identical. If the view script is executed twice, shouldn't two videos instead of one open up? (I added the target="_blank" element to open the pdfs and videos in a new tab).
  19. Hi Larry, Thank you very much for your response. And yes, you "guess" was correct of course! The "Undefined index: mp4" error only appears when the the file size, including an MP4, is much larger that the "upload_max_filesize" and the "post_max_size" as defined in the php.ini file (currently set at 10MB each). Trying to uploading a 20MB file (double the maximum set values) still generates only a form validation error. But any file from 50MB and upwards generates the "Undefined index: mp4" error. Any way to avoid the "Undefined index" error (without increasing the "upload_max_filesize" and the "post_max_size" values) just in case a user tries to upload a 50MB plus video file? Regards,
  20. Hi Larry, I used your view_pdf.php script from Chapter 5 as template for a view_video.php script (below) to view uploaded MP4 videos instead of PDF files (I only changed the PDF variable to MP4 per your script). The script executes perfectly fine except it inserts a duplicate record into the MariaDB "history" table with exactly the same timestamps every time a video is viewed. I only added a "video" ENUM value to the "type" column so to have the following types: page, pdf, video. Any suggestions as I could not find any solution on the web. Thank you. <?php // This pages retrieves and shows a video. // 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. // Require the database connection: require(MYSQL); // Assume invalid info: $valid = false; // Validate the video ID: if (isset($_GET['id']) && (strlen($_GET['id']) === 63) && (substr($_GET['id'], 0, 1) !== '.') ) { // Identify the file: $file = VIDEOS_DIR . $_GET['id']; // Check that the video exists and is a file: if (file_exists ($file) && (is_file($file)) ) { // Get the info: $q = 'SELECT id, title, description, file_name FROM videos WHERE tmp_name="' . escape_data($_GET['id'], $dbc) . '"'; $r = mysqli_query($dbc, $q); if (mysqli_num_rows($r) === 1) { // OK! // Fetch the info: $row = mysqli_fetch_array($r, MYSQLI_ASSOC); // Indicate that the file reference is fine: $valid = true; // Only display the video to a user whose account is active: if (isset($_SESSION['user_not_expired'])) { // Bonus material! Referenced in Chapter 5. // Record this visit to the history table: $q = "INSERT INTO history (user_id, type, item_id) VALUES ({$_SESSION['user_id']}, 'video', {$row['id']})"; $r = mysqli_query($dbc, $q); // Send the content information: header('Content-type:video/mp4'); header('Content-Disposition:inline;filename="' . $row['file_name'] . '"'); $fs = filesize($file); header("Content-Length:$fs\n"); // Send the file: readfile ($file); exit(); } else { // Inactive account! // Display an HTML page instead: $page_title = $row['title']; include('./templates/header.html'); echo "<h1>$page_title</h1>"; // Change the message based upon the user's status: if (isset($_SESSION['user_id'])) { echo '<div class="alert"><h4>Expired Account</h4>Thank you for your interest in this content, but your account is no longer current. Please <a href="renew.php">renew your account</a> in order to access this file.</div>'; } else { // Not logged in. echo '<div class="alert">Thank you for your interest in this content. You must be logged in as a registered user to access this file.</div>'; } // Complete the page: echo '<div>' . htmlspecialchars($row['description']) . '</div>'; include('./templates/footer.html'); } // End of user IF-ELSE. } // End of mysqli_num_rows() IF. } // End of file_exists() IF. } // End of $_GET['id'] IF. // If something didn't work... if (!$valid) { $page_title = 'Error!'; include('./templates/header.html'); echo '<div class="alert alert-danger">This page has been accessed in error.</div>'; include('./templates/footer.html'); } ?>
  21. Hi Larry, I used your add_pdf.php script from Chapter 5 as template for an add_video.php script (below) to upload MP4 videos instead of PDF files (I only changed the PDF variable to MP4 per your script). The script executes perfectly fine and the validation works on all files except .MOV files. When I test with a .MOV upload, the script prints the following errors: An error occurred in script 'C:\xampp\htdocs\site\html\add_video.php' on line 39: Undefined index: mp4 An error occurred in script 'C:\xampp\htdocs\site\html\add_video.php' on line 39: Trying to access array offset on value of type null An error occurred in script 'C:\xampp\htdocs\site\html\add_video.php' on line 91: Undefined index: mp4 An error occurred in script 'C:\xampp\htdocs\site\html\add_video.php' on line 92: Trying to access array offset on value of type null I have search for a solution but could not find anything on Stack Overflow or any other source. Any suggestions would be appreciated. Thank you. <?php // This page is used by an administrator to add a video to the site. // Require the configuration before any PHP code as the configuration controls error reporting: require('./includes/config.inc.php'); // If the user isn't logged in as an administrator, redirect them: redirect_invalid_user('user_admin'); // Require the database connection: require(MYSQL); // Include the header file: $page_title = 'Add a Video'; include('./templates/header.html'); // For storing errors: $add_video_errors = array(); // Check for a form submission: if ($_SERVER['REQUEST_METHOD'] === 'POST') { // Check for a title: if (!empty($_POST['title'])) { $t = escape_data(strip_tags($_POST['title']), $dbc); } else { $add_video_errors['title'] = 'Please enter the title!'; } // Check for a description: if (!empty($_POST['description'])) { $d = escape_data(strip_tags($_POST['description']), $dbc); } else { $add_video_errors['description'] = 'Please enter the description!'; } // Check for a mp4: if (is_uploaded_file($_FILES['mp4']['tmp_name']) && ($_FILES['mp4']['error'] === UPLOAD_ERR_OK)) { // Get a reference: $file = $_FILES['mp4']; // Find the size: $size = ROUND($file['size']/1024); // Validate the file size (5MB max): if ($size > 3072) { $add_video_errors['mp4'] = 'The uploaded file was too large.'; } // Validate the file type: // Create the resource: $fileinfo = finfo_open(FILEINFO_MIME_TYPE); // Check the file: if (finfo_file($fileinfo, $file['tmp_name']) !== 'video/mp4') { $add_video_errors['mp4'] = 'The uploaded file was not an mp4.'; } // Close the resource: finfo_close($fileinfo); // Move the file over, if no problems: if (!array_key_exists('mp4', $add_video_errors)) { // Create a tmp_name for the file: $tmp_name = sha1($file['name']) . uniqid('',true); // Move the file to its proper folder but add _tmp, just in case: $dest = VIDEOS_DIR . $tmp_name . '_tmp'; if (move_uploaded_file($file['tmp_name'], $dest)) { // Store the data in the session for later use: $_SESSION['mp4']['tmp_name'] = $tmp_name; $_SESSION['mp4']['size'] = $size; $_SESSION['mp4']['file_name'] = $file['name']; // Print a message: echo '<div class="alert alert-success"><h3>The file has been uploaded!</h3></div>'; } else { trigger_error('The file could not be moved.'); unlink ($file['tmp_name']); } } // End of array_key_exists() IF. } elseif (!isset($_SESSION['mp4'])) { // No current or previous uploaded file. switch ($_FILES['mp4']['error']) { case 1: case 2: $add_video_errors['mp4'] = 'The uploaded file was too large.'; break; case 3: $add_video_errors['mp4'] = 'The file was only partially uploaded.'; break; case 6: case 7: case 8: $add_video_errors['mp4'] = 'The file could not be uploaded due to a system error.'; break; case 4: default: $add_video_errors['mp4'] = 'No file was uploaded.'; break; } // End of SWITCH. } // End of $_FILES IF-ELSEIF-ELSE. if (empty($add_video_errors)) { // If everything's OK. // Add the video to the database: $fn = escape_data($_SESSION['mp4']['file_name'], $dbc); $tmp_name = escape_data($_SESSION['mp4']['tmp_name'], $dbc); $size = (int) $_SESSION['mp4']['size']; $q = "INSERT INTO videos (title, description, tmp_name, file_name, size) VALUES ('$t', '$d', '$tmp_name', '$fn', $size)"; $r = mysqli_query($dbc, $q); if (mysqli_affected_rows($dbc) === 1) { // If it ran OK. // Rename the temporary file: $original = VIDEOS_DIR . $tmp_name . '_tmp'; $dest = VIDEOS_DIR . $tmp_name; rename($original, $dest); // Print a message: echo '<div class="alert alert-success"><h3>The MP4 has been added!</h3></div>'; // Clear $_POST: $_POST = array(); // Clear $_FILES: $_FILES = array(); // Clear $file and $_SESSION['mp4']: unset($file, $_SESSION['mp4']); } else { // If it did not run OK. trigger_error('The MP4 could not be added due to a system error. We apologize for any inconvenience.'); unlink ($dest); } } // End of $errors IF. } else { // Clear out the session on a GET request: unset($_SESSION['mp4']); } // End of the submission IF. // Need the form functions script, which defines create_form_input(): require('includes/form_functions.inc.php'); ?><h1>Add a Video</h1> <form enctype="multipart/form-data" action="add_video.php" method="post" accept-charset="utf-8"> <input type="hidden" name="MAX_FILE_SIZE" value="5242880"> <fieldset><legend>Fill out the form to add a video to the site:</legend> <?php create_form_input('title', 'text', 'Title', $add_video_errors); create_form_input('description', 'textarea', 'Description', $add_video_errors); // Add the file input: echo '<div class="form-group'; // Add classes, if applicable: if (array_key_exists('mp4', $add_video_errors)) { echo ' has-error'; } else if (isset($_SESSION['mp4'])) { echo ' has-success'; } echo '"><label for="mp4" class="control-label">Add MP4 file</label><input type="file" name="mp4" id="mp4">'; // Check for an error: if (array_key_exists('mp4', $add_video_errors)) { echo '<span class="help-block">' . $add_video_errors['mp4'] . '</span>'; } else { // No error. // If the file exists (from a previous form submission but there were other errors), // store the file info in a session and note its existence: if (isset($_SESSION['mp4'])) { echo '<p class="lead">Currently: "' . $_SESSION['mp4']['file_name'] . '"</p>'; } } // end of errors IF-ELSE. echo '<span class="help-block">MP4 only, 3MB Limit</span> </div>'; ?> <input type="submit" name="submit_button" value="Add This Video" id="submit_button" class="btn btn-default" /> </fieldset> </form> <?php // Include the HTML footer: include('./templates/footer.html'); ?>
  22. Hi Larry, I updated the code to the snippet below but it still gives me an "Undefined offset" error for values 2 onward. I had a look inside a number of your books that I have but can't find my mistake. Any further comment to guide me will be appreciated. Thank you and regards. ... <div class="mega-dropdown-menu row row-no-padding">'; // 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 ($menu_row = mysqli_fetch_array($r, MYSQLI_NUM)) { echo '<div class="col-md-4 col-lg-2 ml-lg-auto"> <ul class="megadropdown-links"> <li><a class="dropdown-item" href="?lid=' . $menu_row[0] . '">' . $menu_row[1] . '</a> </li> <li><a class="dropdown-item" href="?lid=' . $menu_row[2] . '">' . $menu_row[3] . '</a> </li> </ul> </div> <div class="col-md-4 col-lg-2 ml-lg-auto"> <ul class="megadropdown-links"> <li><a class="dropdown-item" href="?lid=' . $menu_row[4] . '">' . $menu_row[5] . '</a> </li> <li><a class="dropdown-item" href="?lid=' . $menu_row[6] . '">' . $menu_row[7] . '</a> </li> </ul> </div> <div class="col-md-4 col-lg-2 ml-lg-auto"> <ul class="megadropdown-links"> <li><a class="dropdown-item" href="?lid=' . $menu_row[8] . '">' . $menu_row[9] . '</a> </li> <li><a class="dropdown-item" href="?lid=' . $menu_row[10] . '">' . $menu_row[11] . '</a> </li> </ul> </div> <div class="col-md-4 col-lg-2 ml-lg-auto"> <ul class="megadropdown-links"> <li><a class="dropdown-item" href="?lid=' . $menu_row[12] . '">' . $menu_row[13] . '</a> </li> <li><a class="dropdown-item" href="?lid=' . $menu_row[14] . '">' . $menu_row[15] . '</a> </li> </ul> </div> <div class="col-md-4 col-lg-2 ml-lg-auto"> <ul class="megadropdown-links"> <li><a class="dropdown-item" href="?lid=' . $menu_row[16] . '">' . $menu_row[17] . '</a> </li> <li><a class="dropdown-item" href="?lid=' . $menu_row[18] . '">' . $menu_row[19] . '</a> </li> </ul> </div> <div class="col-md-4 col-lg-2 ml-lg-auto"> <ul class="megadropdown-links"> <li><a class="dropdown-item" href="?lid=' . $menu_row[20] . '">' . $menu_row[21] . '</a> </li> <li><a class="dropdown-item" href="?lid=' . $menu_row[22] . '">' . $menu_row[23] . '</a> </li> </ul> </div>'; } } mysqli_free_result($r); echo '</div> </div> ...
  23. Thank you for your response Larry. I changed the code to the snippet below but it gives me an "Undefined offset" error for values 2 onward. I tried to find a solution in the book as well as online without any success. Regards. ... <div class="dropdown-menu"> <div class="mega-dropdown-menu row row-no-padding">'; // 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) { $menu_row = mysqli_fetch_array($r, MYSQLI_NUM); echo '<div class="col-md-4 col-lg-2 ml-lg-auto"> <ul class="megadropdown-links"> <li><a class="dropdown-item" href="?lid=' . $menu_row[0] . '">' . $menu_row[1] . '</a> </li> <li><a class="dropdown-item" href="?lid=' . $menu_row[2] . '">' . $menu_row[3] . '</a> </li> </ul> </div> <div class="col-md-4 col-lg-2 ml-lg-auto"> <ul class="megadropdown-links"> <li><a class="dropdown-item" href="?lid=' . $menu_row[4] . '">' . $menu_row[5] . '</a> </li> <li><a class="dropdown-item" href="?lid=' . $menu_row[6] . '">' . $menu_row[7] . '</a> </li> </ul> </div> <div class="col-md-4 col-lg-2 ml-lg-auto"> <ul class="megadropdown-links"> <li><a class="dropdown-item" href="?lid=' . $menu_row[8] . '">' . $menu_row[9] . '</a> </li> <li><a class="dropdown-item" href="?lid=' . $menu_row[10] . '">' . $menu_row[11] . '</a> </li> </ul> </div> <div class="col-md-4 col-lg-2 ml-lg-auto"> <ul class="megadropdown-links"> <li><a class="dropdown-item" href="?lid=' . $menu_row[12] . '">' . $menu_row[13] . '</a> </li> <li><a class="dropdown-item" href="?lid=' . $menu_row[14] . '">' . $menu_row[15] . '</a> </li> </ul> </div> <div class="col-md-4 col-lg-2 ml-lg-auto"> <ul class="megadropdown-links"> <li><a class="dropdown-item" href="?lid=' . $menu_row[16] . '">' . $menu_row[17] . '</a> </li> <li><a class="dropdown-item" href="?lid=' . $menu_row[18] . '">' . $menu_row[19] . '</a> </li> </ul> </div> <div class="col-md-4 col-lg-2 ml-lg-auto"> <ul class="megadropdown-links"> <li><a class="dropdown-item" href="?lid=' . $menu_row[20] . '">' . $menu_row[21] . '</a> </li> <li><a class="dropdown-item" href="?lid=' . $menu_row[22] . '">' . $menu_row[23] . '</a> </li> </ul> </div>'; } mysqli_free_result($r); echo '</div> </div>'; ...
  24. Yes, the last code snippet above displays the language results alphabetically and horizontally across the 6 columns in the drop down menu as follow: Deutsch English (UK) English (US) Español Français Italiano Nederlands Português Pусский Ελληνικά 中文 日本の But I want the language results to display alphabetically and vertically across the 6 columns as follow: Deutsch English (US) Français Nederlands Pусский 中文 English (UK) Español Italiano Português Ελληνικά 日本の The result should also provide for additional languages to be added to the database at a later stage. Thank you and regards.
×
×
  • Create New...