-
Posts
5,450 -
Joined
-
Days Won
175
Everything posted by mac_gyver
-
due to things like cross site scripting and phishing attacks, even if this form and form processing code is only accessible to logged in users, the data submitted can be anything, cannot be trusted, and must be used securely in every context (sql, html, mail header, file operation.) a lot of web sites have been taken over due to injected code in values that were 'only being viewed by staff members'. the posted code example is - insecure (the current problem), provides a poor user experience (when there are validation errors, which the code doesn't even perform, by putting the form and form processing code on separate pages, requires the user to keep reentering data over and over), is filled with copying of variables to other variables for nothing, and has error handling for the database statement that would only confuse the visitor. prepared queries are the simplest, fool-proof way of preventing any sql special characters in a value, a ' in this case, from breaking the sql query syntax. however, the mysqli database extension is overly complicated and inconsistent when dealing with prepared queries. you would want to switch to the much simpler and more modern PDO database extension. the form processing code and form should be on the same page. this will reduce the amount of code that must be written, allow any user/validation errors to displayed with the form, and allow previously entered data values to repopulate the form fields so that the user doesn't need to keep reentering data upon an error. you should use exceptions for database statement error handling and only catch and handle the exception in your code for user recoverable errors, such as inserting/updating duplicate or out of range user submitted values. in all other cases, simply let php catch and handle the exception, where php will use its error related settings to control what happens with the actual error information (database statement errors will 'automatically' get displayed/logged the same as php errors) requiring no logic in your code at all. for more than about 2-3 form fields, you should use a data-driven design, where you have an array that defines the expected fields, validation steps, and processing, that you would simply loop over using general purpose code, rather then writing out, testing, debugging, and maintaining a bunch of bespoke code for every possible field.
-
MySQL UPDATE changes all rows instead of WHERE
mac_gyver replied to RADaugherty's topic in PHP Coding Help
when i tried your code, $headerData being used when the query is executed is the full 'Battery-0975GJ' value. this is a string, not an integer. you are casting it as an integer in the bind_param("si" usage, resulting in a zero for a value. in sql queries, when one parameter in a comparison is a number, the other parameter is converted to a number as well. you are getting WHERE 0 = 0 which is matching every row. -
what is the number being inserted? do you have error handling for all the database statements that can fail - connection, query, prepare, and execute? are any of the columns in this table defined as unique indexes and could be producing a duplicate index error, that you are not handling? does your table have a datetime field that automatically gets the current datetime so that you would know when the data you see was actually inserted? BTW - this series of insert/update queries must be part of a transaction, so that you will only commit them if they all succeed without any errors, and will roll them back (or withhold committing them) if there's an error in any of them.
-
Edit and delete restricted to author of the post or admin
mac_gyver replied to AlexMcKenze's topic in PHP Coding Help
any edit/delete link/form controls and any edit/delete operation code would be conditioned by either the current user's admin permission level or the current user's id matching the owner id of the data being edited/deleted. your login system should store the user's id in a session variable to indicate who the currently logged in user is. on each page request, you would query to get the current user's permissions (this is so that any change made to the permission level will take effect on the very next page request.) any stored data related to the user, such as blog posts, should use the user's id, not the user's username, to relate it back to the user (this is so that you can edit the username without needing to update all the related data to match the changed username value.) -
PHP MySQL update query not working if not all form fields completed
mac_gyver replied to johnc81's topic in PHP Coding Help
the posted code has a session_start near the top, then another one inside the post method form processing, right before assigning the last insert id to a session variable. the one near the top is all you need and in fact the second one will be producing a php error, which is probably being discarded when the redirect occurs. i would set php's output_buffering to off in the php.ini, so that you will see any non-fatal php errors or debugging output from your code prior to a redirect. -
PHP MySQL update query not working if not all form fields completed
mac_gyver replied to johnc81's topic in PHP Coding Help
the following is an example, with one 'email' type field, showing the organizational and post method form processing/form points that were made - <?php // initialization session_start(); $post = []; // array to hold a trimmed working copy of the form data $errors = []; // array to hold user/validation errors // post method form processing, detect if a post method form has been submitted if($_SERVER['REQUEST_METHOD'] === 'POST') { // trim all the data at once $post = array_map('trim',$_POST); // if any input is an array, use a recursive trim call-back function here instead of php's trim // validate inputs if($post['email'] === '') { $errors['email'] = "Email is required."; } else if(!filter_var($post['email'], FILTER_VALIDATE_EMAIL)) { $errors['email'] = "Email format is not valid."; } // if no errors, use the form data if(empty($errors)) { // use the data in $post here... } // if no errors, success if(empty($errors)) { $_SESSION['success_message'] = "Some success message."; die(header("Refresh:0")); } } // html document starts here... ?> <?php // output and clear any success message if(isset($_SESSION['success_message'])) { echo "<p>{$_SESSION['success_message']}</p>"; unset($_SESSION['success_message']); } ?> <?php // output any errors if(!empty($errors)) { echo "<p>".implode('<br>',$errors)."</p>"; } ?> <?php // output the form, repopulating any field values with the existing form data ?> <form method='post'> <label>Email: <input type='email' name='email' value='<?=htmlentities($post['email']??'',ENT_QUOTES)?>'></label><br> <input type='submit'> </form> your original logic, checking if it is set and assigning one value if it is, and another if it is not, is okay. i wouldn't make a new name/change the name for it when doing so, and you can use php's ternary operator to simplify the logic - // condition checkbox input $post['orderPaid'] = isset($post['orderPaid']) ? 1 : 0; by definition, all external data are string data types, regardless of what value they contain. if the 1st value='' option is selected, you will get an empty string in the php code. if one of the other options is selected, you will get a string containing the numerical value. as long as the string value only contains numerical characters, it should be handled okay by php and by the database. to actually validate that the non-empty submitted value is one of the permitted choices, i would make an array of the data from the tbl_countries select query, with the id as the array indexes, and the element values being the country names, then either test if the array entry corresponding to the submitted value isset() or testing if the submitted value is in the array of the array keys, using in_array() and array_keys(). -
PHP MySQL update query not working if not all form fields completed
mac_gyver replied to johnc81's topic in PHP Coding Help
the main problem with the current code is that it doesn't have any 'working' error handling for the insert query. the error handling you do have for that query is testing if the sql query statement, which is a string, is a true value, which it always will be. instead, use exceptions for database statement error handling and only catch and handle the exception for user recoverable errors, such as when inserting/updating duplicate or out of range user submitted data values. in all other cases, simply let php catch and handle the exception, where php will use its error related settings to control what happens with the actual error information (database statement errors will 'automatically' get displayed/logged the same as php errors.) you would then remove any existing database error handling conditional logic in your code (for the connection and insert query), since it will no longer get execution upon an error. if you are familiar with the PDO extension, use it. it is much simpler and more modern than the mysqli extension, especially when dealing with prepared queries, which you should be using, since they provide protection against sql special characters in data values, for all data types, from breaking the sql query syntax. 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. your code generally follows this, but it has things like two session_start() statements, that needs to be cleaned up. the post method form processing should - detect if a post method form has been submitted before referencing any of the form data. keep the form data as a set in a php array variable, then operate on elements in this array variable throughout the rest of the code. trim all the input data, mainly so that you can detect if it consists of all white-space characters. validate inputs, storing validation errors in an array using the field name as the array index. after the end of the validation logic, if there are no errors, use the form data. after using the form data, if there are no errors, perform a redirect to the exact same url of the current page to cause a get request for that page. any redirect needs an exit/die statement after it to stop code execution. to display a one-time success message, store it in a session variable, then test, display, and clear the session variable at the appropriate location in the html document. if there are errors at step #5 or #6 on this list, the code would continue on to display the html document, where you would display any errors and redisplay the form, populating the form field values with any existing data. since there won't be any existing data values the first time the form is displayed, you need to address this at the point of using the values in the form. php's null coalescing operator ?? is a good choice to use here. any external, dynamic, unknown value output in a html context should have htmlentities() applied to it to help prevent cross site scripting. here's a laundry list of addition things for the posted code - the php error related settings should be in the php.ini on your system use 'require' for things your code must have for it to work creating a sales order is an administrative activity. you should have a login and user permission system to control access to this operation don't copy variables to other variables for nothing, just use the original variables don't use multiple variables to indicate something when one will work, e.g. orderIDx/orderActivex the session can hold data from different parts of your application. don't completely destroy the session, only unset specific things when needed. since you will be directly testing/using the session variable, instead of copying them to other variables, you won't be destroying or unsetting session variables for the part of the code you have shown. don't blindly loop over external data. hackers can cause 1000's of post variables to be submitted to your code. instead, only operate on expected post entries. you should actually be using a data-driven design, where you have an array that defines the expected fields, their validation, and processing, that you would loop over to dynamically do this operation. don't use variable variables, especially on external data. this allows hackers to set ANY of your program variables to anything they want. don't redirect around on your site, accepting values in the url to control what gets displayed as the result of performing an operation. this opens your site to phishing attacks. if you have a need for using numerical values to indicate which of multiple states something is in, use defined constants with meaningful names, so that anyone reading the code can tell what the values mean in the validation code, setup a unique and helpful error message for each validation error for each input, i.e. don't make the user guess what was wrong with the submitted data if any of the fields/columns must be unique, define them as unique indexes in the database table, then test in the database exception error handling if the query produced a duplicative index error number (1062 if i remember correctly.) for all other error numbers, just re-throw the exception and let php handle it. an empty action="" attribute is actually not valid html5. to cause the form to submit to the same page, leave out the entire action attribute don't put name or id attributes into the markup unless they are used you should validate the resulting web pages at validator.w3.org <option tags don't have name attributes you can put php variables directly into over-all double-quoted strings, without all the extra concatenation dots and quotes. just about every SELECT query should have an ORDER BY ... term so that the rows in the result set are in a desired order don't echo static html. just drop out of php 'mode' when you build and output the <option lists, output the selected attribute for the option that matches the existing form data when you output the checkbox field, you would output the checked attribute if that field is set in the existing form data the point where you are using - echo '0 Results'; won't display anything because it is inside the <select></select> tags. if there are no option choices, you should probably not even output the markup for the entire field, and output the message instead when conditional logic 'failure' code is much shorter then the 'success' code, invert the condition being tested and put the 'failure' code first. this will make your code clearer and cleaner -
PHP MySQL update query not working if not all form fields completed
mac_gyver replied to johnc81's topic in PHP Coding Help
once the form has been submitted, except for unchecked checkbox/radio fields, all the fields will be set and they will be a string data type, regardless of what value they contain. empty always-set fields will be an empty string. unless you have code setting the values to null and are using those values in the sql query statement in such as way that the null value will get used as is, e.g. not quoted, or you are dynamically building the sql query statement and leaving the fields out, or are explicitly using the DEFAULT keyword for the value, nulls or the defined default value won't get used. you will need to post all the code we would needed, form and form processing, to reproduce the problem, along with your database table definition for anyone here to directly help. -
if you were doing this for real, where the price can change over time, the pricing would be stored in a related table, associated back to the token rows through the token's id, with a token_id, price, and effective start and effective end datetime columns. the point of the id column in this table is to assign a token id (auto-increment integer primary index), that would be stored in any related data table. this is the value that the form would submit for the selected token and would be stored in the usertoken table, not the token name. the balance is a derived value. you would not maintain the balance as a single value in a column, but would instead calculate it when needed. to do so, you need an account(ing) table, with a separate row inserted for each deposit/withdrawal that affects the account balance. also, the full name should be stored, using two columns, e.g. first_name, and last_name, so that you can uniquely distinguish between and search for people by name, e.g. is someone Ross Martian or Martian Ross? the account(ing) and usertoken table would use the id value from the users table, to related any stored data back to the correct user. this table should contain all the who, what, when, where, and why information about the purchase. the who would be the user_id of the buyer. the what would be the token_id, quantity, and purchase price (if you have a separate table for the pricing, you don't need this value). the when would be the datetime of the purchase. the where would only apply if there's a location associated with the purchase. the why would be a status/type value or memo field describing the reason for the purchase. this table doesn't need the account number, as that is defined in the users table and is known based on the user id. also, the totalbuy is a derived value that isn't stored. it is calculated when needed using the quantity and the purchase price (or the separately stored price at the datetime of the purchase.) the discount amount should be calculated and inserted as a separate row, in a related discount/interest accounting table, related back to the usertoken through the id in the usertoken table. you must do this as a single 'atomic' operation, in one query. the way to do this is use the query technique shown in this thread - https://forums.phpfreaks.com/topic/315532-avoid-appointment-conflict where you have an INSERT ... SELECT query that will only insert a new row in the usertoken table if the where clause calculates if the user's current balance - by summing the user's accounting rows, discount/interest rows, minus the user's existing token purchase amounts, is greater then or equal to the total amount of the submitted purchase. and just to clarify, the only two values submitted from the form should be the selected token id and the quantity. everything else should use values that only exist on the server.
-
it would probably be better if you continued any posting about this subject in the Nov 15th thread - https://forums.phpfreaks.com/topic/315539-is-anything-wrong-with-this-code/ that came after the last Nov 13th post above. the outline of code for the form/form processing that i gave in that thread produces no errors when it runs. this should have eliminated much of the work of getting to the point of having all the input data ready to use in the calculations. i also see though looking at your previous threads that several of the suggestions recently given were previously given but never used.
-
How can I make 2 form actions with 1 button
mac_gyver replied to PNewCode's topic in PHP Coding Help
the processing of the submitted post method form data should have nothing directly to do with the display of any data. you should - display the form when the form is submitted, detect if a post method form has been submitted trim, then validate the form data, storing any user/validation errors in an array using the field name as the array index if there are no user/validation errors, use the form data (which could result in more user errors, such as for duplicate or out of range values) if here are no errors at this point, redirect to the exact same url of the current page to cause a get request for the page to display a one-time success message, store it in a session variable, then test, display, and clear that session variable at the appropriate location in the html document at this point, you would get any data needed to display the current page, then output it in the html document. if you want the user to be able to go to different page(s), that queries for and displays other data, provide navigation link(s) to do so. -
the new-line/end-of-line setting in your programming editor is set to a non-standard setting. changing it to any of the other choices would be an improvement and allow the forum software to display your code properly.
-
you would need to run the php script at 1.5 minute intervals (twice the frequency of the data) to insure that you don't miss any data. you would read the contents of the file and explode it into an array. if you want to only keep some of the elements, you can use array_intersect_key() to only keep those elements that you want. to store the data, rather than to have a table with 177+ columns, have one table which you insert a row for each data sample, with an id (auto-increment primary index), a datetime column, and any other columns that describe the data, such as a unit id, so that you can record data for multiple stations. the id column in this table produces a data_id. you would get this id and use it when storing the actual data. the data table would have an id (auto-increment primary index), data_id, field number (0-177), and value columns. the icon mapping values would be stored in another database table, that you would JOIN with the field number 48 values to get the corresponding text/image.
-
what your code should do for this activity is generate a random number, then do what is described in this post - https://forums.phpfreaks.com/topic/315552-php-mysql-returns/#comment-1602746 to just attempt to insert that random number into the table. if the code continues past the point where the INSERT query is executed, you know that the generated number was unique and was inserted into the table. if the code transfers execution to the exception catch block and the error number is for a duplicate index, instead of setting up a message for the user that there was a duplicate, you would cause the code to loop back to the start, where it would generate a new random number and attempt to execute the insert query again. i would use a loop counter, of about 10, so that a programming mistake or the random number generator doesn't work very well (the rand() documentation mentions that the maximum on windows is a 32bit number, not a double-int) to force an exit if the operation doesn't succeed.
-
the OP is trying to do this activity by rote, by memorization, by appearance, not though actually learning (internalizing) the meaning of the words and syntax. this produces a result that is only as good as his memory recall is. the mysqli_query() call on the prepared query statement object is the same misusage at the start of a previous recent thread, which @requinix hinted/asked (Jeopardy theme can be heard playing in the background) if the OP actually wanted to do this. one would assume that since the OP removed this statement in that thread that he would have learned something by doing so, but since the OP is doing this by repeating pictures of the words, no learning occurred, hence the repeated mistake. @alexandre, writing code actually means writing the words and syntax of the language you are using, so that they result in an understandable story that when the computer executes them they do something useful. to do this you must actually learn the meaning of the words and syntax, not just repeat, copy/pasting things together based on what you have seen. somehow, you must make this transition in how you are approaching this activity. instead of just seeing and repeating a picture of the words, you must actually learn the meaning of the words, so that you know what they do or even if they belong in the current task.
-
your database design must enforce uniqueness, it is the last step in the process. when there are multiple concurrent instances of your script running, they can all query to find that the value does not exist and attempt to insert it. the first one will win this timing race and succeed. all the following ones must fail with an error. to do this, the column you are trying to match must be defined as a unique index. you would then just simply attempt to insert the data and in the error handling, which should be using exceptions, you would test if the error number is for a unique index violation (1062), and setup a message letting the user know that the value is already in use. for all other error numbers, just rethrow the exception and let php handle it.
-
you are using a post method form, followed by an unnecessary redirect, to select which record to edit and then a get method form for updating the data. this is backwards. you should use get inputs to determine what will be displayed on a page and a post method form when performing an action on the server, such as updating the data. also, you can and should do all of this on one page to avoid repetition of 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 when you display the existing records, the edit button should be a get method link with the id as part of the link. when you click one of those links, the resulting code that gets executed would query to get the existing row of data to populate the form field values, but only if the update form has never been submitted. if the update form has been submitted, you would not execute this query. the way to accomplish this 'interlocking' of the data being edited is to use an internal 'working' array variable to hold this data, then use elements in this array variable through out the rest of the code. inside the post method form processing logic, you would store a trimmed copy of the $_POST form data in this variable. at the point of querying for the initial data, if this variable is empty, you would execute the query. here are some issues with and things that will simplify the posted code - your login system should only store the user id in the session variable upon successful login, then query on each page request to get any other user information, such as the user's name, permissions. your code should check if the current logged in user is an admin before allowing access to the edit logic. when conditional 'fail' code is much shorter than the 'success' code, if you invert the condition being tested and put the fail code first, it results in clearer, cleaner code. also, since the fail code is a redirect in this case, which must have an exit/die statement to stop php code execution, you can eliminate the else {} part of the conditional test since the redirect/exit/die will stop the execution for a non-logged in user. don't copy variables to other variables for nothing. this is just a waste of typing and introduces errors. don't use multiple names for the same piece of data. whatever the actual meaning of the data is, use that name throughout the code. one such example is the staff_id value being called 'data' and at another point it is a name value. since you will be switching to use a post method form for the update operation, after you detect if a post method form has been submitted, all the form fields (except for unchecked checkbox/radio fields) will be set. there will be no need for a massive list of isset() statements. you should put the database connection code in a separate .php file, then require it when needed. you should not unconditionally echo database errors onto the web page, which will only help hackers when they internationally trigger errors. instead, use exceptions for database statement errors an in most cases let php catch and handle the exception. the exception to this rule is when inserting/updating user submitted data that can result in duplicate or out of range values, which is something that you are doing. in this case, your code should catch the exception, test if the error number is for something that your code is designed to handle, and setup a message letting the user know what was wrong with the data that they submitted. for all other error numbers, just re-throw the exception and let php handle it. the logout operation should use a post method form. any function definitions should either be in the initialization section of code or be in their own .php files that get required in the initialization section of code. your application should not use the root user without any password. instead, create a specific database user with a password with only the permissions that it needs for you application. the updateRecord function should only have two call-time parameters. an array of the input data and the database connection. the updateRecord should not contain any application specific html markup. this should be handled in the calling code. the function should only return a true or false value to the calling code. don't put external, unknown, dynamic values directly into sql query statements. you must protect against sql special characters in data values from being able to break the sql syntax, which is how sql injection is accomplished. the fool-proof way of doing this is to use prepared queries. since the mysqli extension's prepared query interface is overly complicated and inconsistent, this would be a good time to switch to the more modern and simple PDO database extension. the updateRecord function should not close the database connection. it is not the responsibility of this function to do this, only to update the recorded. the update form should populate the form field values and preselect the option that matches the initial existing data being edited, then populate/preselect using the submitted form data, as described above. any dynamic value that you output on a web page should have htmlentities() applied to it to help prevent cross site scripting. the value attribute for the select/option 1st prompt option should be an empty string. since you are putting the <label></label> tags around the form field they belong with, you don't need the for='...' and matching id='...' attributes. the post method form processing code should - detect if a post method form was submitted. keep the form data as a set in an array variable. trim all the input data as at once. after you do item #2 on this list, you can do this with one php statement. validate all the inputs, storing validation errors in an array using the field name as the array index. after the end of all the validation logic, if there are no errors, use the form data. after using the form data, if there are no errors, redirect to the exact same url of the current page to cause a get request for the page. if you want to display a one-time success message, store it in a session variable, then test, display, and clear the session variable at the appropriate location in the html document. if there are errors at step #5 or #6 on this list, the code would continue on to display the html document, where you would test for and display any errors, and redisplay the form, repopulating the field values/selected option choices with the values that are in the 'working' array variable holding the submitted form data.
-
foreach(array_keys($matches[1]) as $key) { echo "SKU number {$matches[1][$key]} costs {$matches[2][$key]}<br>"; }
-
need help to make links hidden if not admin
mac_gyver replied to alexandre's topic in PHP Coding Help
you should have one login system with a single set of ids. if your user login system and admin login system reuses ids, those users having ids the same as an admin will appear to be the admin with that same id. Keep It Simple. -
need help to make links hidden if not admin
mac_gyver replied to alexandre's topic in PHP Coding Help
so, now you have to maintain two almost identical pages, where every change you make to the poll output, must be repeated in both pages. that's the wrong direction to move toward when doing programming. you want to reduced the amount of work you have to do to create and maintain a web site, not increase it. what's wrong with adding a simple conditional test where the two links appear at in the html document, so that they are only output if the current user is an admin? Keep It Simple (KISS.) edit: i also recommend that you convert your mysqli based code to use PDO. it is very simple to do so and actually eliminates a bunch of lines of code. you will also be able to directly fetch the result from the query into an appropriately named array variable, such as $user_data, so that you don't need to worry about naming a bunch of variables to keep from overwriting other variables that may already exist. -
now that we know a bit more about what you are doing, a multi-page form, collecting data that eventually gets used for some purpose, now would be a good time to switch to using a data-driven design, to eliminate all the repetitive code for the data collection, rather than to spend time fixing each page of it.
-
i was able to make the code repopulate the fields/select-option, when navigating around, using 3 lines of code and one conditional test, added to the get method business logic section. i won't post the code i came up with because it is probably not how your application is determining which step/page it is on. you could also just merge the successful $post data into the $_SESSION['step'] array inside the post method form processing code, then when the page is visited without any $post data, copy the whole $_SESSION['step'] array back into $post (which i just tested and it works as well.) if you want help with anything your application is or is not doing, you must post enough of the code so that someone here can reproduce what it is doing.
-
for the activity you have shown in this thread and using the previously given programming practices about how to organize, cleanup, and code your form processing and form, a lot of this typing of code goes away, you would end up with the following - <?php /* put any error relating settings in the php.ini on your system you may have a need to store the result from some step in session variable(s), but by unconditionally storing each piece of post data, you are doubling the amount of code needed. only store the end result. Keep It Simple (KISS.) to dynamically generate a select/option list, you would not use discrete variables for each value and write out logic for each option. you would instead have an array of the values, then loop to dynamically build the options. in html5, an empty action='' attribute is not valid. to get a form to submit to the same page it is on, leave the action attribute completely out of the form tag. you should validate your resulting web pages at validator.w3.org */ // initialization session_start(); $post = []; // an array to hold a trimmed working copy of the form data $errors = []; // an array to hold user/validation errors // post method form processing if($_SERVER['REQUEST_METHOD'] === 'POST') { // trim all the data at once $post = array_map('trim',$_POST); // if any of the fields are arrays, use a recursive trim call-back function here instead of php's trim function // validate inputs if($post['owner'] === '') { $errors['owner'] = 'The owner is required.'; } if($post['renter'] === '') { $errors['renter'] = 'The renter is required.'; } if($post['state'] === '') { $errors['state'] = 'The state is required.'; } // add validation for other inputs here... // if no errors, use the form data if(empty($errors)) { // if this is a step in a multi-step process, store the now validated data in a specific session variable $_SESSION['step'][1] = $post; } // if no errors, success if(empty($errors)) { // if you want to display a one-time success message, store it in a session variable here, // then test, display, and clear that session variable at the appropriate point in the html document $_SESSION['success_message'] = 'Some success message for this step in the process'; // redirect to the exact same url of the current page to cause a get request for the page die(header("Refresh:0")); } } // get method business logic - get/produce data needed to display the page // query to get the states in the order that you want them // fake some values $states = []; $states[]="Maine"; $states[]="Texas"; // html document ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Form processing/form example</title> </head> <body> <?php // display and clear any success message if(isset($_SESSION['success_message'])) { echo "<p>{$_SESSION['success_message']}</p>"; unset($_SESSION['success_message']); } ?> <?php // display any errors if(!empty($errors)) { echo "<p>".implode('<br>',$errors)."</p>"; } ?> <form method="post"> <label>Owner: <input type="text" style="width:255px;" name="owner" value="<?=htmlentities($post['owner']??'',ENT_QUOTES)?>"></label><br> <label>Renter: <input type="text" style="width:255px;" name="renter" value="<?=htmlentities($post['renter']??'',ENT_QUOTES)?>"></label><br> <label>State: <select name="state"> <option value="">select state</option> <?php foreach($states as $state) { $sel = isset($post['state']) && $post['state'] === $state ? 'selected' : ''; echo "<option value='$state'$sel>$state</option>"; } ?> </select></label><br> <input type="submit"> </form> <?php // note: if you have the need for a 'clear' session function, add that as a separeate post method form, with a hidden field with a value to indicate that action // then test for that action value in the form processing code to clear the session data ?> <?php // display the content of the session if(!empty($_SESSION)) { echo '<pre>'; print_r($_SESSION); echo '</pre>'; } ?> </body> </html> and as already mentioned, if you have more than 2-3 form fields, you should use a data-driven design, where you have a data structure (database table, array) that defines the expected form fields (for each step), validation rules, and processing for each field, then dynamically validate and process the form data, rather than to write out bespoke logic for each field.
-
the following is a 'tricky' example of INSERTing data that satisfies a maximum count of rows - $query = "INSERT INTO team_members (team_id, staff_id, stafftype) SELECT -- the following values being SELECTed are the actual data values to insert ?,?,? FROM DUAL -- dual is an allowed dummy table name to satisfy the FROM ... WHERE syntax WHERE (SELECT COUNT(*) FROM team_members WHERE team_id = ? AND stafftype='leader') < 1 -- insert the data if the WHERE (subquery count) < 1 is TRUE"; $stmt = $pdo->prepare($query); $stmt->execute([$team_id, $staff_id, $stafftype, $team_id]); if($stmt->rowcount()) { echo "A leader row was inserted for team_id: $team_id, staff_id: $staff_id<br>"; } else { echo "A leader already exists for team_id: $team_id<br>"; } this example was to insert a maximum of one 'leader' row per team id. you would change it to insert a maximum of two rows per datetime appointment slot. because this uses a single query to both get a count of the number of existing rows and insert a new row, it will work correctly for multiple concurrent instances of your script.
-
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. the post method form processing should - detect if a post method form has been submitted before referencing any of the form data. keep the form data as a set in a php array variable, then operate on elements in this array variable throughout the rest of the code. trim all the input data, mainly so that you can detect if it consists of all white-space characters. validate inputs, storing validation errors in an array using the field name as the array index. after the end of the validation logic, if there are no errors, use the form data. after using the form data, if there are no errors, perform a redirect to the exact same url of the current page to cause a get request for that page. any redirect needs an exit/die statement after it to stop code execution. to display a one-time success message, store it in a session variable, then test, display, and clear the session variable at the appropriate location in the html document. if there are errors at step #5 or #6 on this list, the code would continue on to display the html document, where you would display any errors and redisplay the form, populating the form field values with any existing data. since there won't be any existing data values the first time the form is displayed, you need to address this at the point of using the values in the form. php's null coalescing operator ?? is a good choice to use here. any external, dynamic, unknown value output in a html context should have htmlentities() applied to it to help prevent cross site scripting. once you have detected that a post method form has been submitted, except for unchecked checkbox/radio fields, all form fields will be set and won't produce php errors. for checkbox/radio fields, you need to use isset() statements to test if they are set before referencing them in the form processing code. since the posted code isn't detecting if a post method form has been submitted at all before referencing the form data and isn't doing anything for item #10 on this list, you are getting unnecessary php errors. btw - if you have more than 2-3 form fields, you should use a data-driven design, where you have a data structure (database table, array) that defines the expected form fields, validation rules, and processing for each field, then dynamically validate and process the form data, rather than to write out bespoke logic for each field.