-
Posts
5,454 -
Joined
-
Days Won
175
Community Answers
-
mac_gyver's post in PHP $_FILES operation problem was marked as the answer
don't attempt to test if a submit button is set. there are cases where it won't be. one of these cases is if the total size of the form data exceeds the post_max_size setting on the server, both the $_POST and $_FILES arrays will be empty. you should instead test if a post method form was submitted - if($_SERVER['REQUEST_METHOD'] === 'POST'), then test if there is $_POST and/or $_FILES data, before referencing any of the form data.
after you have tested that there is data in $_FILES, you must test the ['error'] element to make sure that the file upload was successful. there's a list of the possible error values in the documentation - https://www.php.net/manual/en/features.file-upload.errors.php
after you have determined that the file uploaded without any error, you can test/use the uploaded file information.
-
mac_gyver's post in Handling Fatal error/using includes was marked as the answer
when you successfully complete the post method form processing code, you should perform a redirect to the exact same URL of the current page, the page the form processing code and the form is on, to cause a get request for that page. this is called - Post, Redirect, Get (PRG) - https://en.wikipedia.org/wiki/Post/Redirect/Get this will prevent the browser from resubmitting the form data should that page get reloaded or browsed away from and back to.
to display a one-time success message/content, store a value in a session variable, then test for the session variable, display the variable/content, and clear that session variable, at the appropriate location in the html document on that page.
to allow the visitor to go to any other page, provide navigation links.
-
mac_gyver's post in PHP 8.2 - mysqli_report(MYSQLI_REPORT_OFF) doesn't work was marked as the answer
you have jumped to an incorrect conclusion about what is occurring.
an sql query that has no programming mistake doesn't produce any php errors when accessing the result from that query, regardless of php version.
you are getting php errors because there's something wrong with the specific sql query in question with the code you are posting. if you do what has already been suggested and add error handling, you can find out what is wrong with the query. if you want anyone here to help, you will need to post the sql query.
i'm going to guess that you are putting a value, in a php variable, directly into the sql query statement, in a numerical context, such as an id, but the value is empty, resulting in an sql syntax error. this is a programming mistake. the correct way to fix this is to validate inputs, only execute a query when 'required' inputs have an expected value, and to use a prepared query so that any sql special characters in a value cannot break the sql query syntax.
-
mac_gyver's post in Php Require or Include inside of IF/ELSE statement was marked as the answer
because you have no logic to do this. the else() you have is part of the last if(){} conditional, for the phone number.
you should NOT use discrete variables for the error messages. this would require you to either have an additional flag to indicate any errors or you would need to write a conditional test with all the discrete variables. you should instead use an array (arrays are for sets of things where you are going to operate on each member in the set in the same or similar way) to hold the user/validation errors, using the field name as the main array index. after the end of the validation logic, if the array holding the errors is empty, you can use the submitted form data, e.g. -
if(empty($errors)) { // use the submitted data here... } to display the errors at the appropriate location in the html document, either test the contents of the array and display all the errors together or display each error adjacent to the field it corresponds to.
speaking of/writing about using arrays for sets of things, you should keep the form data as a set in a php array variable, then operate on elements in this array variable throughput the rest of the code. this will allow you to trim all the data at once, using one php array function, and will support dynamically validating and processing the data.
speaking of/writing about dynamically validating the data, you should NOT write out - copy/paste logic for every possible value. you should instead use a data-driven design, where you have a data structure (database table, array) that holds the dynamic values, then use this definition to control what general purpose logic does. the only thing that is different between these validation types is the regex pattern. why not store them in an array with the data type, regex pattern and error message, then just get the correct entry and call one general purpose function with the correct type regex pattern and the input value?
whatever the code is for this function is probably improper. in general, besides trimming input data, you should NOT modify user submitted data as this changes the meaning of the data. if data is valid, use it. if it is not, tell the user what is wrong with it and let the user fix then resubmit the data.
-
mac_gyver's post in Replace Into blanking some fields was marked as the answer
From the documentation -
it seems like you should be using an UPDATE query for this operation?
-
mac_gyver's post in Function runs great when called isolated but only that way was marked as the answer
the problem is you are using the $password variable for two different things.
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 you should have one user database table with both client and psychologist registration/login data and a 'type' column holding a value that indicates which type of user they are. Don't Repeat Yourself (DRY.)
it is not the responsibility of the sendOTPmail() function to create a database connection. you already have a database connection in the application, supply it to any function that needs it as a call-time parameter.
-
mac_gyver's post in Total count as well as total per client was marked as the answer
you would add GROUP BY client.id to the query to get a SUM() per client. in fact, if your database was set to STRICT mode, you would be getting an error with the current query about using an aggerate function without a GROUP BY term.
then, if you want both the SUM() per client and the grand total, you can add WITH ROLLUP to the end of the GROUP BY ... term.
-
mac_gyver's post in enetering empty fields was marked as the answer
if you are not posting the actual code that you are having a problem with, the replies you get may not have anything to do with the problem.
here's example code (tested with faked data from the SELECT query) showing most of the points that i made -
<?php // initialization // recursive trim function function _trim($val) { if(is_array($val)) { return array_map('_trim',$val); } else { return trim($val); } } session_start(); // make database connection here... $table_name = 'your_table'; $error = []; // an array to hold user/validation errors $post = []; // an array to hold a trimmed working copy of the form data // get all subject data $sql = "SELECT id, subject_name FROM tbl_subjects_secondary"; $stmt=$pdo->query($sql); $subject_data = $stmt->fetchAll(); // post method form processing if($_SERVER['REQUEST_METHOD'] === 'POST') { // trim all the input data at once $post = _trim($_POST); // loop over the subject ids and validate the corresponding form data foreach(array_column($subject_data,'id') as $key) { if($post['test_score'][$key] === '') { $error['test_score'][$key] = "Test Score Field is Required"; } if($post['exam_score'][$key] === '') { $error['exam_score'][$key] = "Exam Score Field is Required"; } } // if no errors, use the submitted data if(empty($error)) { $sql = "INSERT INTO $table_name ( subject_id, test_score, exam_score ) VALUES ( ?, ?, ? )"; $stmt = $pdo->prepare($sql); foreach(array_column($subject_data,'id') as $key) { $stmt->execute([ $key, $post['test_score'][$key], $post['exam_score'][$key] ]); // note: error handling for this query is not included with this example code } } // if no errors, success if(empty($error)) { // if you want to display a one-time success message, store it in a session variable, then test, display, and clear that variable in the html document $_SESSION['success_message'] = 'You have successfully inserted the subject scores'; // redirect to the exact same url of the current page to cause a get request - PRG Post, Redirect, Get. die(header("Refresh:0")); } } // get method business logic - get/produce data needed to display the page // get all subject data - located above the post method form processing since it is also used by the validation logic // html document ?> <!DOCTYPE html> <html lang="en-US"> <head> <meta charset="utf-8"> <title>Multi-row Insert 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 the form ?> <form method="post"> <table class="table table-borderless"> <thead> <tr> <th>SN</th> <th>Subject</th> <th>Continuous Assessment Score</th> <th>Examination Score</th> </tr> </thead> <tbody> <?php $i = 1; foreach($subject_data as $row) { ?> <tr> <th><?= $i++ ?></th> <td><input type="text" class="form-control border-0" readonly value="<?=$row['subject_name']?>"></td> <td><input type="number" name="test_score[<?=$row['id']?>]" class="form-control" value="<?=htmlentities($post['test_score'][$row['id']]??'',ENT_QUOTES)?>"><span style="color: red; font-size: .8em;"><?= $error['test_score'][$row['id']]??'' ?></span></td> <td><input type="number" name="exam_score[<?=$row['id']?>]" class="form-control" value="<?=htmlentities($post['exam_score'][$row['id']]??'',ENT_QUOTES)?>"><span style="color: red; font-size: .8em;"><?= $error['exam_score'][$row['id']]??'' ?></span></td> </tr> <?php } ?> <tr> <td></td><td></td> <td colspan="2"><button type="submit" class="btn btn-primary w-50">Save</button></td> </tr> </tbody> </table> </form> </body> </html> this produces valid markup, validation per field, and repopulates the field values upon a validation error.
-
mac_gyver's post in Replacing text field with image and keeping value for database was marked as the answer
here's a different approach -
<?php echo '<pre>'; print_r($_POST); echo '</pre>'; ?> <img src="btn/colorpicker/darkred.png" data-color='darkred' onClick="pic_color(this)" class="pointer clrimg"> <img src="btn/colorpicker/yellow.png" data-color='yellow' onClick="pic_color(this)" class="pointer clrimg"> <img src="btn/colorpicker/purple.png" data-color='purple' onClick="pic_color(this)"class="pointer clrimg"> <script> function pic_color(el) { // set the form field to hidden document.getElementById('name_pref').type = 'hidden'; // set the form field value to the current element's data-color value document.getElementById('name_pref').value = el.dataset.color; // get the src attribute from the current element and set the pref_img src attribute document.getElementById('pref_img').setAttribute('src',el.getAttribute('src')); // display the pref_img element document.getElementById('pref_img').style.display = 'block'; } </script> <form method='post'> <input type="text" name="name_pref" id='name_pref' style="font-size: 24px;" value=""> <img style="display:none" id='pref_img' class="pointer clrimg"> <br> <input type='submit'> </form>
-
mac_gyver's post in IF statement not working was marked as the answer
as of php8 -
either update to php8+ or use a strict comparison ===
-
mac_gyver's post in Php Mysql Automation guidance was marked as the answer
the date format string to get the first day of the current month is - 'Y-m-01'
you would not write out conditional logic (switch/case, if) for every possible value. if you did have a need to match a set of input values to output values, you would use an array, where the array index is the input value and the stored array value is the output value.
you would display the redeem button based on a non-redeemed status value in the row of data. then update that status value to a redeemed value when the offer is redeemed.
-
mac_gyver's post in I'm getting a session error was marked as the answer
the correct place to assign a value to the session variable is in the post method form processing code, at the point where you have confirmed that the username and password have been matched (it is currently not at this point in the code and needs to be corrected.) it should not be assigned a value in any other place. therefore, remove the assignment statement you currently/still have in sayfam.php. the debugging line of code, with print_r($_SESSION, true), should still be in sayfam.php, until you get this to work, since is shows if the session variable is set and what value it contains.
-
mac_gyver's post in Help with hiding search titles was marked as the answer
conditional statements exist in programming languages so that you can write code that makes decisions when it runs, such as only outputting markup when there's data to display.
the existing code has a conditional test in it to only output the markup inside the tbody if there is data to display. wouldn't the answer to your question be to move the start of that conditional test so that it only outputs the table/thead markup when there is data to display?
-
mac_gyver's post in Using PHP and Ajax to show ORDERS by Year without refreshing page was marked as the answer
you are getting a fatal error in the browser. you need to use your browser's develop tools console tab to debug what is going on in the browser.
the element you have given id="selectYear" to, is the button, not the select menu.
as to the $cusid. this is already known on the server when the main page was requested. why are you passing it through the form? external data submitted to your site must always be validated before using it. if you use the already validated value that you already know on the server, you can simplify the code.
-
mac_gyver's post in Unable to display username in Table was marked as the answer
just use a single JOIN query to do this.
next, you should always list out the columns you are SELECTing in a query so that your code is self-documenting. you should build your sql query statement in a php variable, to make debugging easier and help prevent syntax mistakes, and you should set the default fetch mode to assoc when you make the database connection so that you don't need to specify it in each fetch statement.
the reason why your current code doesn't work, is because fetchAll(), the way you are using it, returns an array of the rows of data. if there are three rows in the company table, you will have an array with three rows in it, with each row having an assignedto element. you can use print_r() on the fetched data to see what it is.
-
mac_gyver's post in Sending emails to multiple email ids with nested loop was marked as the answer
how many email addresses per vendor? if there's only one, you don't need the 2nd foreach() loop to fetch it, just directly fetch the single row without using a loop.
next you don't even need the 1st foreach() loop, just implode $_POST['vendor'] to make a comma separated list, then use FIND_IN_SET(vendor,?) in the WHERE clause to match all the rows in one query, then just use the result set from that single query. if you use PDO fetchAll() with the PDO::FETCH_COLUMN fetch mode, you will get a one-dimensional array of just the email addresses, that you can directly implode() to produce the comma separated list of email addresses.
-
mac_gyver's post in How to validate if certain value is duplicate or if certain input field is not filled using PHP AJAX Javascript was marked as the answer
I've written at least twice that the ->create() method must return a success or failure value that you test in the calling code. the database specific code in the ->create() method is where that information is known at.
here's what your create.php should look like (without the multiple column duplicate determination code) -
<?php // when using ajax, the only thing this code will do is handle the post method form processing // you can save resources on non-post requests by putting all the code inside the request method test // initialization //Headers header('Access-Control-Allow-Origin: *'); header('Content-Type: application/x-www-form-urlencoded'); header('Access-Control-Allow-Methods: POST'); header('Access-Control-Allow-Headers: Access-Control-Allow-Headers,Content-Type,Access-Control-Allow-Methods, Authorization, X-Requested-With'); // use 'require' for things your code must have for it to work require '../../config/database.php'; require '../../models/post.php'; //Instantiate db $database = new Database(); $db = $database->connect(); // define the $table and $fields for the Create operation $table = 'skandi'; $fields = []; $fields['sku'] = ['label'=>'SKU','validation'=>['required']]; // add other field definitions here... //Instantiate post for the Create operation $product = new Post($db,$table,$fields); $post = []; // array to hold a trimmed working copy of the form data $errors = []; // array to hold user/validation errors // post method form processing if($_SERVER["REQUEST_METHOD"]==="POST") { //Get raw data $json = json_decode(file_get_contents("php://input"),true); // trim all the input data at once $post = array_map('trim',$json); // if any input is an array, use a recursive trim call-back function here instead of php's trim // validate all inputs foreach($fields as $field=>$arr) { if(isset($arr['validation']) && is_array($arr['validation'])) { foreach($arr['validation'] as $rule) { switch ($rule) { case 'required' : if($post[$field] === '') { $errors[$field] = "{$arr['label']} is required"; } break; // add code for other validation rules here... } } } } // if no errors, use the input data if(empty($errors)) { //Create if(!$product->create($post)) { // initially, just setup a canned message for the sku column $errors['sku'] = "SKU is already in use"; // the code to detect which of multiple columns contain duplicates would replace the above line of code } } // if no errors, success if(empty($errors)) { $response = [ 'message' => "Created Successfully" ]; } else { $response = [ 'message' => implode('<br>',$errors) ]; } echo json_encode($response); } the corresponding ->create() method would be -
public function create($data) { // build the sql query $set_terms = []; $params = []; foreach(array_keys($this->fields) as $field) { $set_terms[] = "`$field`=?"; $params[] = $data[$field]; } $sql = "INSERT INTO `$this->table` SET " . implode(',',$set_terms); $stmt = $this->conn->prepare($sql); try { // a 'local' try/catch to handle a specific error type $stmt->execute($params); // if you are at this point, the query executed successfully return true; } catch (PDOException $e) { if($e->errorInfo[1] == 1062) // duplicate key error number { return false; } throw $e; // re-throw the pdoexception if not handled by this logic } } as to the server-side validation logic, you should validate each input separately and setup a unique and helpful message for each validation error. the code posted in this reply shows how to use a data-driven design to dynamically validate the data and build the sql query. however, it just occurred to me that the product characteristics (size, weight, height, length, and width) change depending on the selected productType, so the data-driven definition would need entries for each productType value (you should also have a separate product characteristic table, rather than columns in this main table for these characteristic values, where you would only insert rows for each characteristic that exists for each defined product.)
for debugging, just temporarily output (echo/print_r/var_dump) things in the php code, and send everything to the console log in the javascript -
success: function (data) { console.log(data); alert("successfully posted"); },
-
mac_gyver's post in sign up issues with username/email validation was marked as the answer
you have far too much code for this task. it is filled with repetitive logic, copying of variables to other variables for nothing, and while it is adding user/validation errors to an array, it isn't testing that array for the main activity of executing the INSERT query, which is why it is always inserting the new data values. i recommend that you start over, with just the logic you need - Keep It Simple (KISS) and Don't Repeat Yourself (DRY.)
you should make one database connection in your main code, then supply it to any function that needs it, as a call-time parameter. you should use the much simpler and more modern PDO database extension. you should also use exceptions for database statement errors (the PDO extension always uses exceptions for any connection error and starting with php8 always uses exceptions for the rest of the statements that can fail - query, prepare, execute, and exec.)
your post method form processing code should -
detect if a post method form has been submitted keep all the form data as a set, in a php array variable trim all the input data at once. after you do item #2 on this list, you can trim all the data using one single line of code validate each input separately, storing user/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 (the array holding the errors will be empty), use the submitted form data as already stated, the correct way of determining if uniquely defined database columns/fields are duplicate, is to just attempt to insert the data and test if the query produced a duplicate index error number in the exception catch logic. for all other error numbers, just rethrow the exception and let php handle it. since you have more than one unique field, it is at this point where you would execute a (one) SELECT query to find which fields contain duplicate values. you would add error messages to the array holding the user/validation errors for each field that is found to contain duplicate values. after the end of post method form processing logic, 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 that session variable at the appropriate location in the html document. if there are errors at step #5 or #7, the code will continue on to display the html document, display any errors, redisplay the form, populating the fields with any existing form data. any dynamic value that gets output in a html context needs to have htmlentities() applied to it to help prevent cross site scripting. -
mac_gyver's post in is there an ideal way to counter a brute force attempt? was marked as the answer
the existence or absence of a session is under the control of the client/script making the requests to your site. you cannot use session (or cookie) data to detect or control the login attempts, since the client/script can simply not propagate the session id (or cookie) between requests and they will get a new session. you must store the data needed to detect or control the login attempts in a database table.
you have two pieces of identifying information from the requests, the ip address (where the request came from and where you will send the response back to, along with any session id cookie or remember me cookie token) and the username/email for the login attempt. you would store the datetime, ip, and username/email for each failed login attempt, as a separate row, in a database table. it is this data that you would test to detect and control the login attempts.
also, you don't 'lock' the accounts, you rate limit the login attempts. if a user is already logged in, they should still be able to access the site, i.e. they are won't be attempting to login, since they already are logged in.
-
mac_gyver's post in Echo not outputting anything! was marked as the answer
there's nothing wrong with the POSTED code (just tested.) errors like this are usually caused by copy/pasting code that's been published on the web, with smart/curly quotes, which then produce php errors since those type of characters have no meaning in php, but which get converted back to straight quotes when code gets posted on a programming help forum, and therefor work when tried.
delete and re-type the line of code.
-
mac_gyver's post in Trying to create a schedule of games... was marked as the answer
what output are you getting on the web page? if it's a blank page, what does the 'view source' in your browser show? can you echo a string using php code? is your code doing any redirects that could discard any output from the web page if php's output_buffering is ON?
do you have php's error_reporting set to E_ALL and display_errors set to ON, preferably in the php.ini on your system, so that php will help you by reporting and displaying all the errors it detects? stop and start your web server to get any changes made to the php.ini to take effect and check that the settings actually got changed to those values by using a phpinfo(); statement in a .php script file.
do you have error handling for all the database statements that can fail - connection, query, prepare, execute, and a few others? the simplest way of adding error handling, without adding conditional logic at each statement, is to use exceptions for errors and in most cases simply let php catch and handle the exception, where php will use its error related settings (see the previous paragraph above) to control what happens with the actual error information (database statement errors will 'automatically' get displayed/logged the same as php errors.)
to enable exceptions for errors for the mysqli extension, add the following line of code before the point where you make the database connection -
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
-
mac_gyver's post in PHP MySQL update query not working if not all form fields completed was marked as the answer
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
-
mac_gyver's post in Avoid appointment conflict was marked as the answer
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.
-
mac_gyver's post in Apostrophe Errors was marked as the answer
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.
-
mac_gyver's post in MySQL UPDATE changes all rows instead of WHERE was marked as the answer
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.