Jump to content
Old threads will finally start getting archived ×

mac_gyver

Staff Alumni
  • Posts

    5,496
  • Joined

  • Days Won

    184

Everything posted by mac_gyver

  1. you didn't answer what is wrong with the last posted code/output? i understand your code perfectly. the list of programming practices will help to - secure your web site, provide a good User eXperience (UX), simplifies the code, and corrects some mistakes. i looked back at the search form, here's a similar list for it (repeats some things already posted) - to get a form to submit to the same page it is on, simply leave out the entire action attribute. as already written, this should be get method form and it should be 'sticky' and reselect any existing option choices. you need to validate the resulting web pages at validator.w3.org you should list out the columns you are SELECTing and only list the ones you are using in the code. you should (almost) always fetch data using an associate index name so that if your database table gets rearranged the code will still work and your code will be self-documenting (anyone reading it can tell what it is doing without needing to know what your table definitions are). any query that can match more than one row of data needs an ORDER BY ... term so that the data is in an expected order. some of your queries have an ORDER BY, some don't. using a character data type for numerical data won't sort correctly once you have values with more than a single character length. you should use a numerical data type for numerical data. the default ORDER BY ... direction is ASC. you don't need to specify it in a query. if a query doesn't match any data, you should output a message stating so, instead of outputting nothing. you need to apply htmlentities() to dynamic values being output in a html context, right before/as they are being output in order to prevent any html entities in a value from being able to break the html syntax. if you use php's short-open-print-tag <?= it will save typing. also, you can leave out the closing ; right before a closing tag ?> saving typing. there's a ; on the end of all the while ():; statements. this should either be a syntax error or is short-circuiting the loop and should be removed. for the 'required' attribute to work for a select/option menu, the first option choice must have an empty value and serve as a prompt to make a choice. you only need to use the 'required' attribute, you don't need the ="required" value. for a <label> to work, you must either have a for='...' attribute and a corresponding id='...' attribute in the field or more simply just put the closing </label> tag after the form field it corresponds to. if you have a <label>, you cannot have an empty display item for the first <option></option> choice. don't use a series of name-numbered variables. you are/should be completely dealing with the result of one query before going on to the next. just reuse simple variable names.
  2. and what exactly is the problem with the last posted code? here are some points for the current code - you should use a single database extension. now that you have used the much simpler and better designed PDO extension, all your code should be updated to use the extension. you should NOT use the mysqli_real_escape_string() function, which probably doesn't have the character-set set, to match your database tables, when the connection was made, then put these pieces of data directly into the sql query statement, as this can allow sql special charters in a value to break the sql query syntax. you should use a prepared query. converting a query that has php variables being put into it into a prepared query is straight forward. if you need, someone can post a list of instructions how to do this. you should use a get method form when determining what will be displayed on a page. this is so that if someone finds a result they want to return to or share with someone, they can bookmark the URL or share the URL and be able to return to the same result. the search form should be on the same page as the result and the form should be 'sticky' and repopulate the fields, selected options, checkboxes, and radiobuttons with any existing values so that if the search doesn't find what the user expects, they can simply make changes to the search values and try again. all the search form processing code should be inside the conditional statement testing if the form has been submitted. the current code will produce a bunch of php errors and likely produce no search result and output if the page is requested without any form data. you need to trim, mainly so that you can detect if all white-space characters were entered, then validate all input data before using it. the search inputs you have shown are all 'required'. if they are not all valid, you should output error messages stating what is wrong with them and NOT run any of the query/output code. if you want to make any of these search inputs 'optional' you will need to dynamically build the WHERE part of the query and only include the terms that have search values. the use of LEFT JOIN doesn't make sense (to me). it indicates that you want to get marks data that may not have any student or school associated with it. you should just use a JOIN if you only want marks data that has school/student data. if a query doesn't match any data, you should output a message stating so, rather than outputting nothing. you need to apply htmlentities() to dynamic values being output in a html context, right before/as they are being output in order to prevent any html entities in a value from being able to break the html syntax.
  3. this is the thead section - <thead> <tr class="text-center"> <th class="th-sm text-center">Subject </th> <th class="th-sm text-center">Class Score <br>(30%) </th> <th class="th-sm text-center">Exam Score <br>(70%) </th> <th class="th-sm text-center">Total <br>(100%) </th> <th class="th-sm text-center">Grade </th> <th class="th-sm text-center">Position </th> <th class="th-sm text-center">Remarks </th> </tr> </thead> it is the same for every student. your output is incorrect because the markup you are producing is broken. the code inside the loop is incorrect. the reason I posted an outline of what the code should do is to help you to be able to produce the correct output that will work. i recommend that you validate the resulting web page at validator.w3.org
  4. in looking at the markup you are creating, id's must be unique. if you are using the id attributes for styling, you need to use css classes instead. also, since the thead section is the same, you should build it once, in a php variable, before the start of any looping, then just echo that variable when needed.
  5. i recommend indexing/pivoting the data using the 'studentid' as a main array index when you fetch the data. this will give you an array of sub-arrays, with one sub-array for each student. this eliminates the need for conditional logic to test when the student changes and eliminates repetitive code and logic to close out each student section, but not for the very first one, before starting a new student section, and again after the end of the output. // index/pivot the data using the studentid as the main array index $data = []; while ($row = mysqli_fetch_assoc($run)) { $data[$row['studentid']][] = $row; } this also allows you to use print_r() or var_dump() on the data to make sure it is what you expect, before trying to produce the output. you can then use two nested foreach loops to produce the output. you also need to define the markup you are trying to produce, before writing any code, something like - // foreach data as student // reference the zero'th row of student data to get the one-time values for the heading // output heading information // start table // start the thead section // output the tr // end the thead section // start the tbody section // foreach student as row // output the tr // end foreach // end the tbody section // start the tfoot section // end the tfoot section // end the table // end foreach
  6. yes. which you can determine by testing. unchecked checkboxes are not set in the submitted form data. your code should only be concerned if the checkbox data isset() or is (not) !isset(). the logic would be - if (isset($p) && !isset($d) && !isset($c) && !isset($o)) { echo "error"; }
  7. the 'successful' case is: $d == "Yes" || $c == "Yes" || $o == "Yes" because you are using negative logic to produce an error, the complement of this is: $d != "Yes" && $c != "Yes" && $o != "Yes" // what i think you want if ($p == "Yes" && $d != "Yes" && $c != "Yes" && $o != "Yes") { echo "error"; }
  8. your written statement is ambiguous. please post some examples showing what result you want for different input combinations. specifically, what is the 'successful' case, which can then be complemented to produce the error case? what do you want when $p is not Yes? is that an error or does it mean that you don't care about the other three values?
  9. are you asking this because something you have shown us doesn't work or for a critique of the method? here's a list of points for the posted code - i recommend naming the connection variables more uniquely, such as $db_host, $db_name, $db_user, $db_pass. you are going to require this code into a main file. depending on where it gets required at, you could have other $user and $pass variables that will conflict with this code. there's no good reason to catch and handle a connection exception in your code and re-throwing the exception you just caught with only the message and code looses the file and line information, hindering debugging. the only database exceptions you should catch and handle in your code are for user recoverable errors, such as when inserting/updating duplicate user submitted data. for all other query errors, all other type of queries, and for the connection, you should do noting in your code and let php catch and handle the database exceptions, where php will use its error related settings to control what happens with the raw database error information, via an uncaught exception error (database errors will 'automatically' get displayed/logged the same as php errors.) don't use the global keyword to make your code 'work'. doing this breaks function scope, is not general purpose, and makes it harder if you ever need to use more than one database connection in a script. you should supply inputs to a function as call-time arguments. query builders, like this, usually have a 'raw' query function/method to handle cases beyond what the code itself can handle. i hope you are NOT planning on directly using the submitted form data to supply the column definitions to these functions, as this is not secure. your code must be where the defining array is defined at, so that YOU have control over what happens with the data and what columns and data gets used when dynamically building the queries. having the definition in your code also allows you to define labels, for use in building error messages and dynamically producing form fields and validation rules, for dynamically validating data on the server before using it. because you are dynamically building these queries, you should surround the table and column names with back-ticks so that you don't need to worry about what the actual identifiers are at the point of building the query. because you are using exceptions for errors, the conditional logic you have for the ->execute() call in the insertData() function will never see a false value and should be removed. one of the main points of exceptions is that your main code only 'sees' error free execution, since execution goes elsewhere upon an error. if execution continues past a statement that can throw an exception, you know there was no error without needing to test using conditional logic. as already mentioned, you need the ability to test for a duplicate index error (number) from a query in the exception catch logic to handle the case of inserting/updating duplicate user submitted data. for both an insert and an update query, they produce a PDOStatment rowCount() and a PDO lastInsertId() values (yes you can get a lastInsertId() value from an update query, which can be used to get an arbitrary value from the query, such as the id of the row that was updated or the initial or final value that was updated.) you should return an array with both of these values in it. you need to consistently validate the $table and $data/$conditions inputs before using them. the deleteData function() should return the rowCount() value, not the boolean value from the ->execute() call, which again due to using exceptions will always be a true value. when you get to the point of writing the update function() you need to distinguish between the columns/values used in the SET ... part of the query and the columns/values used in the WHERE ... part of the query. WHERE ... terms often involve more than just = (equal) comparisons and only ANDing multiple terms. there are LIKE, IN(), BETWEEN, greater/less, ... comparisons and combinations using AND/OR between terms. insert, update, delete, and select queries can get prepared once, then executed multiple times with different input values. to handle this you can define the variable holding the PDOStatement object as a static variable inside the function, then only prepare the query if the PDOStatement object doesn't already exist. you need a way of destroying the PDOStatement object when you are done using it. you have set the default fetch mode to assoc when you made the database connection, why are you also putting it in the fetch call?
  10. is phpmyadmin working? your initial symptom is that the raw php code is being output to the browser. did this change to the file being downloaded? about the only thing that comes to mind (ignoring that you apparently directly created a file on the server and it didn't work) is that when you uploaded (ftp) the files to the web hosting they got changed, possibly due to using a binary transfer mode instead of text transfer mode.
  11. The point of programming help forums is for you to post your code and the error or symptom you are getting and someone with the ability (and often without) will attempt to help you with the problem.
  12. you should use var_dump() on the values for debugging, since it indicates the length of the value. unfortunately, you didn't show us what you saw when you echoed the variables and if you made a change to the sql query statement and it didn't work, showing us what you changed would help someone solve the problem. converting a query that has variables being put directly into it into a prepared query is straight forward - remove, and keep for later, any php variables that are inside the sql query statement. note: any wild-card characters in a LIKE comparison are supplied as part of the data value not as part of the sql query statement. remove any quotes or {} that were around the php variable and any concatenation dots/extra quotes that were used to get the php variable into the sql query statement. put a simple ? prepared query place-holder into the sql query statement for each value. call the PDO prepare() method for the sql query statement. this returns a PDOStatement object. call the PDOStatement execute([...]) method with an array of the variables you removed in step #1. for a query that returns a result set, fetch the data from the query. see the PDOStatement fetch() method when fetching a single row of data. the PDOStatement fetchAll() method when fetching all the rows of data at once. and occasionally the PDOStatement fetchColum() method when fetching a single column from a single row of data. forget about any num rows function/method/property. just fetch then test if/how many rows of data there are. for a query that doesn't return a result set, you can use the PDO lastInsertId() method and the PDOStatement rowCount() method to get the last insert id and the number of affected rows. for the query in this thread, this would look like - // i recommend that you build the sql query statement in a php variable. this makes debugging easier since you can echo the sql $sql = "Select * FROM weekends WHERE Weekend_Number = ? AND Men_Women = ?"; $stmt = $pdo->prepare($sql); $stmt->execute([ $_SESSION['Weekend_Number'], $_SESSION['Men_Women'] ]); // if this query can match a set of data $result = $stmt->fetchAll(); // if this query can match at most one row of data $result = $stmt->fetch(); typical PDO connection code - $DB_HOST = ''; // database host name or ip address $DB_USER = ''; // database username $DB_PASS = ''; // database password $DB_NAME = ''; // database name $DB_ENCODING = 'utf8mb4'; // db character encoding. set to match your database table's character set. note: utf8 is an alias of utf8mb3/utf8mb4 $options = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // set the error mode to exceptions - this is the default setting now in php8+ PDO::ATTR_EMULATE_PREPARES => false, // run real prepared queries PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC // set default fetch mode to assoc ]; $pdo = new pdo("mysql:host=$DB_HOST;dbname=$DB_NAME;charset=$DB_ENCODING",$DB_USER,$DB_PASS,$options);
  13. i second the use of prepared statements. you MUST protect against sql special characters in a value being able to break the sql query syntax, which is how sql injection is accomplished. a prepared query is the simplest (provided you use the much simpler and better designed PDO extension), fool proof way of accomplishing this for all data types. also, if the 'th' (ordinal indicator) is actually part of the value, it should not be. this is a human convention and should only be displayed, not actually submitted or stored. you should only submit or store the integer value. the code copying session variables to other variables is both unnecessary (just use the original variable that data is in) and indicates that your form and form processing code is on different pages. by separating these, you are nearly doubling the amount of code and since it takes more code to accomplish a task, you are likely leaving out things that provide security or a good User eXperience (UX.) the code for any page should be laid out in this general order - initialization post method form processing get method business logic - get/produce data needed to display the page html document
  14. have you done or checked the 3 possible things that were already posted above? are you actually including SecureFunctions.php? also, do you have multiple sets of these files in different paths and there is more than one SecureFunctions.php and the wrong one got updated?
  15. if this is the only session variable you are getting an error for (i didn't get an error for this variable, but did for some other ones when i ran your code), here are some possibilities - your actual code has some non-printing characters in or smart/curly-quotes around the index name (that posting code on this forum filtered out). i would delete and retype the entire index name, including the initial and final double-quotes, in each reference to this array index name. is any of the other code that gets executed in the functions being called, referencing or setting that variable and could be unsetting it? are you sure that the latest code got saved/uploaded so that you are actually initializing that variable? most of these session variables exist solely to pass data from the form processing code back to the form. you should instead put the form processing code and the form on the same page. this will greatly simplify all the code. the code for any page should be laid out in this general order - initialization post method form processing get method business logic - get/produce data needed to display the page html document at the completion of the post method form processing code, you should preform a redirect to the exact same URL of the current page to cause a get request for that page. this will prevent the browser from trying to resubmit the form data should that page get browsed back to or reloaded. you should not copy variables to other variables for nothing. just use the original variables that data is in. in the current code, a significant number of lines are there only to copy variables back and forth, yet you have instances of using the original variable that data is in. you should apply htmlentities() to any dynamic value being output in a html context, right before/as it is being output, to prevent any html entity in value from breaking the html syntax.
  16. what this would look like using the method i posted above - <input type="text" maxlength="32" size="42" name= "<?=$Comment_Name?>" value="<?=$_SESSION["DE_Retain"] == 1 ? $_SESSION["DE_Comment"] : ''?>">&nbsp;&nbsp;Max 32 Characters<br><br> likewise for the checkbox logic - Retain comment:&nbsp;<input type="checkbox" maxlength="1" size="1" name="Retain" <?=$_SESSION["DE_Retain"] == 1 ? 'checked' : ''?>> i'm pretty sure that checkboxes don't have maxlength or size attributes. if any of these variable may not exist, to prevent php errors, you need to use the null coalescing operator ?? to set default values. if you want to clear all the session data, you can use session_destroy();. if you only want to clear this 'form' data you are passing around, while keeping the current user logged in, you should store this data in a session array variable, such as $_SESSION['post']. you can then clear this data by just unsetting it - unset($_SESSION['post']);
  17. my reply was a possible reason why php would work on your localhost system but not on actual web hosting. you have already checked, by trying, that the files are not being treated as php on the web hosting. you should not have needed to create a .htaccess file or put an addhandler ... line in it. this may in fact be why php isn't working. did you do this as an attempt to get the php to work after you discovered that it didn't or did you do this prior to trying to run any php code? has any php code ever worked on your web hosting? i would use your cpanel file editor to create a new .php file, and put the following in it, then request the URL of the this file in a browser to see if php works - <?php phpinfo();
  18. do these files have a .php extension, i.e. you didn't configure your localhost system to treat .htm/.html extensions as being php code?
  19. here's a slightly different approach. only write conditional code for the things that are - conditional. the only thing that's different in the output is the value (which actually doesn't make practical sense, since this is a field for a user to enter something into.) this also falls under Don't Repeat Yourself (DRY) coding. your if/else logic, which can then use the simple ternary operator, should only supply the desired 'Des' or 'Dave' value.
  20. in case you didn't do a web search for the database server setting that's specifically listed in the error messages - https://dev.mysql.com/doc/refman/8.4/en/group-by-handling.html
  21. after reviewing the code more, let me introduce you to 'event delegation'. this will let you simplify all the code for attaching events to the buttons. this works by attaching the event to a parent container, such as the div with class='right-content', that all the buttons will exist in, regardless of when they are created. you would then find which button has been clicked by testing an attribute value from the button, such as a class name. the code would look like - document.addEventListener("DOMContentLoaded", function() { console.log("✅ DOM fully loaded and parsed."); // use event delegation for dynamically added elements (buttons) // attach the event to a common parent element - class='right-content' const buttonWrapper = document.querySelector('.right-content'); // add the click event to everything in the common element, now or in the future buttonWrapper.addEventListener('click', function (event) { // examine the className of the clicked element console.log('target class: ',event.target.className); switch(event.target.className) { case 'view-details-btn': view_details(event.target); break; case 'change-status-btn': openStatusModal(event.target); break; case 'update-notes-btn': openNotesModal(event.target); break; case 'delete-btn': deleteRenewal(event.target); break; case 'closeModal': document.getElementById(event.target.getAttribute("data-modal-id")).style.display = "none"; break; case 'confirmChangeStatus': confirmChangeStatus(event.target); break; case 'confirmUpdateNotes': confirmUpdateNotes(event.target); break; } }); });
  22. the most immediate problem is you are reusing id="updateNotesModal" for two modals. the modal you see is the one defined in get_renewal_details.php, but the javascript code that's running when you click the "update notes" button is what is defined in Renewals.php and this doesn't match the elements in the modal that is displayed. best suggestion is that get_renewal_details.php should only get and display the details. there should only be one id="updateNotesModal" modal defined, so there won't be any confusion about which one gets displayed and operated on.
  23. the php error you are getting is a follow-on error, because the query is failing, but there is no error handling for the query. the easiest way of adding error handling for all the mysqli statements that can fail - connection, query, exec, prepare, and execute, is to use exceptions for errors (this is the default setting now in php8+). to enabled exceptions for the mysqli extension, add the following line of code before the point where you make the database connection (or upgrade to php8) - mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); you should then be getting an uncaught exception error with the raw database error information in it about a non-groupby/non-aggerate column being referenced. the correct way of fixing this is to a) only select the columns you are using, and b) every column you are selecting needs to be either in the GROUP BY term or used in an aggerate function. there is a database server mode setting that control if this condition produces a query error (the current setting) or if it is just a warning. you may or may not have access to this database mode setting.
  24. the syntax error(s) are due to missing quotes on the end of each string and reusing the same type of quote inside the strings. you are building and echoing literal strings. the initial and final quotes on each string must be the same type and be a matching pair. you are missing the final quote on each string. the > at the end are part the <img ... > tag and belong inside the string, e.g. echo "<img ...>";. any quotes that are within a string must either be the 'opposite' type, single vs double, or they must be escaped so that they don't match the initial quote, which terminates the string. the initial and final quotes around the src="..." attribute should either be changed to single-quotes or escaped with \ characters. i prefer less typing, so i would use single-quotes. next, your conditional logic only needs - if( normal case){ echo normal output } else { echo special output }. lastly, your conditional comparisons need some help. you need to test if the 'm' and 'd' part of the date is greater than or equal a lower value AND less then or equal to a higher value. also, for testing purposes, you need to be able to manually set the value being tested, so this value should be built in a variable, which will be a string, e.g. '0106' for jan 6th. as long as the fields making up a string are the same width, and from left to right, most significant to least significant, you can directly compare strings, e.g. if('0106' <= $some_variable ... i'll let you cogitate on how to create and test the conditional logic needed.
  25. the file system path/filename must be to where the file is located on the disk, either using a relative path (relative to the file with the include/require starting in it) or an absolute path. a leading / refers to the root of the current disk, which is doubtful where that file is located, and which will be producing a php error about a non-existent path/file. you must get php to help you by reporting and displaying all the errors it detects. you can temporarily set php's error_reporting/display_errors in your code (you will want to remove the settings when you are done learning, developing, and debugging). you can add the following immediately after the first opening <?php tag in the main file - ini_set('display_errors', '1'); error_reporting(-1);
×
×
  • 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.