Jump to content

mac_gyver

Staff Alumni
  • Posts

    5,382
  • Joined

  • Days Won

    173

Community Answers

  1. mac_gyver's post in PHP help needed. Webpage php script works for all teams except team "0" was marked as the answer   
    this checks the datatype of the variable, not what's in the variable. get, post, cookies are by definition strings, regardless of what value they hold. change this to is_numeric().
  2. mac_gyver's post in Design of a database for a price list was marked as the answer   
    i/we don't understand abbreviations like tpu, pu, n, n 2, r, r 2 that would give meaning to the posted information. can you provide some context, in English, for the two examples you have posted? are these different categories of items?
    ultimately,  your task boils down to database normalization. you can search on the web to find out what this means.
    to start with, you need an item table that holds the unique information about the items, one row per item. at a minimum, this table would have columns for - id (autoincrement primary index), and name.  this will establish the item ids that will get used when storing data related to the items.
    if these various wookbooks are for different categories of items, you also need a category table that holds the unique information about the categories, one row per category. at a minimum, this table would have columns for - id (autoincrement primary index), and name.  this will establish the category ids that will get used when storing data related to the categories. if this is the case, the above item table would also have a category_id column that will hold the corresponding category id for each item.
    since i/we don't know if pricing is per category, per item, or per list of items. i.e. what the extent and scope of the data is, i cannot offer any specific suggestions beyond the above.
  3. mac_gyver's post in PHP calculation was marked as the answer   
    here's some coding pointers -
    don't copy variables to other variables for nothing. just use the original variable(s) that data is in. don't write out code for every possible value. use a data-driven design and let the computer operate on each value for you. here's what I came up with. in your initialization section -
    // define the month number and names (columns) $months = [1=>"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Decm"]; // note: the reason you needed to use decm is because dec is a reserved word. you can use dec if you surround it in back-tacks in any sql statement inside the while(){...} loop -
    // array to hold the data for the current row $data = []; // loop over the month number and month names foreach($months as $mo=>$month) { // produce the year-month value $ym = $row['Year'] .'-'. str_pad($mo,2,'0',STR_PAD_LEFT); // test if the year-month is between the start and end dates if($ym >= $row['start'] && $ym <= $row['end']) // use whatever you have named the start and end date columns { // put the value into the data array // use zero for any empty value $data[] = $row[$month] == '' ? 0 : $row[$month]; } } // at this point, $data contains the entries to use for the current row of fetched data // examine the result echo '<pre>'; print_r($data); echo '</pre>'; // calculate the average $TotalMark = round((array_sum($data)) / count($data), 2); // examine the result echo $TotalMark; note: you should use a value like 9999-12 for the end date for a person who is still employed
  4. mac_gyver's post in Experiencing problems with CODE tags was marked as the answer   
    the correct way of including code in the forum is to use the menu's <> button.
  5. mac_gyver's post in num_rows with object mysqli and statements was marked as the answer   
    i also recommend the much simpler and more modern PDO extension. you can directly fetch data from a prepared query, the same as how you would fetch it for a non-prepared query.
    if you are going to use the mysqli extension, forget about mysqli_int/mysqli_stmt_prepare. just use mysqli_prepare(). also, forget about the num_rows property. just fetch the data and test if there was any fetched data.
    if you are querying to find a row of data matching an (active) user, you would not include the password comparison in the WHERE ... term. also, you should be using php's password_hash() and password_verify() for password hashing.
    php finally realized the it should use exceptions for errors for things like database statement errors. as of php8, the mysqli (and PDO) connection, query, exec, prepare, and execute calls throw exceptions for errors. this means that any conditional error handling logic you have for these statements can be removed since they won't ever get executed upon an error, simplifying the code.
    there's also generally no need to close prepared query handles, free up result sets, or close database connections in your code, since php destroys all resources when your script ends, simplifying the code.
    pdo version -
    $sql="SELECT * FROM users WHERE username=? AND active=1"; $stmt = $pdo->prepare($sql); $stmt->execute([ $uname ]); if($user_data = $stmt->fetch()) { // a row was found // you can reference elements in $user_data, such as $user_data['id'], $user_data['added'], ... } else { // no row was found }  
     
     
     
     
     
  6. mac_gyver's post in Query Failed : SQLSTATE[HY093]: Invalid parameter number: parameter was not defined was marked as the answer   
    when using named prepared query place-holders, the name must match between what you use in the sql query and the binding. in your code, they don't. e.g. :LogID is not the same as :LOGIN_ID. ...
    i recommend that you use simple positional ? place-holders. there's less to type and keep track of. regardless of the place-holder type, you can simply supply an array of the input values to the ->execute([...]) call, saving more typing.
    you should not manage the id value yourself in code. this is not concurrent safe. instead, use an autoincrement primary index. the database engine will perform the necessary table locking to insure that concurrent queries will generate unique values.
    your database must enforce uniqueness, it is the last step in the process. the username column must be defined as a unique index. you would then attempt to insert a row of data, and test in the exception handling catch block for that query if an duplicate index error (number) occurred. if it did, setup a message for the user letting them know that the username is already in use. for all other error numbers, rethrow the exception and let php handle it.
    there's also nothing to fetch from an insert query. why are you doing that?
  7. mac_gyver's post in Self submitting AJAX was marked as the answer   
    provided the code for the page is 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 end of item #2, if the request was an AJAX request, you would build and output the response to the ajax request, then exit/die, so that the rest of the code on the page isn't executed.
    here's a snippet of code to detect an AJAX request -
    define('IS_AJAX_REQUEST', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'); you can then conditionally run AJAX request only code using -
    if(IS_AJAX_REQUEST) { // build and output the response to the AJAX request // typeically json_encode([some meaningful error or success data]); // stop php code execution die; }  
  8. mac_gyver's post in Row count based on the two condition was marked as the answer   
    OR you can use the complement -
    select count(*) as CustomerActual, Month from sbms.customerdata WHERE EmpID='83201858' AND (VisitType = 'No Due' OR VisitDate !='') group by Month  
  9. mac_gyver's post in HTTP response code was marked as the answer   
    to get php to cause a http 500 status for fatal syntax/runtime errors, php's display_errors setting needs to be set to OFF. you would then want the log_errors setting to be set to ON, so that you have a record of what errors are occurring. also, php's error_reporting needs to always be set to E_ALL or a -1.
  10. mac_gyver's post in Php random math test with form entry was marked as the answer   
    are you doing this as a learning exercise? what is your goal?
    some pointers -
    the code for any page should be laid out in this general order - 1) initialization, 2) post method form processing, 3) get method business logic - get/produce data needed to display the page, 4) html document. the post method form processing should not attempt to detect if the submit button is set, there are cases where it won't be. instead, detect if a post method form was submitted before referencing any of the form data. keep all 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 before validating it, mainly so that you can detect if all white-space characters were entered. validate all the trimmed input data at once, storing user/validation errors in an array, using the field name as the main array index. after the end of the validation logic, if there are no errors (the array holding the user/validation errors is empty), use the input data. since all you are doing is comparing an input value with the correct answer, you can do this as part of the validation logic. if you were storing data in a database, authenticating a user, sending an email, ... you would put the code needed to perform these actions here. after using the input data, if there are no errors, perform a redirect to the exact same URL of the current page to cause a get request for the page. this will prevent the browser from trying to resubmit the form data should the page get reloaded or browsed back to. 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 user/validation errors, the code will continue on to display the html document, display any errors, redisplay the form, populating the field values with any existing data, so that the user doesn't need to keep reentering values over and over. any dynamic value you output in a html context needs to have htmlentities() applied to it to help prevent cross site scripting. there's a programming issue with the division operator and computers. this operation can result in a fractional part that cannot be represented exactly in a computer and then cannot be easily compared. you may want to test the answer produced is this case and limit the question/answer to those which only have whole integer answers, i.e. keep something like 9/3, but not 7/6, and also don't allow division by 0.
    if you do all of that, except for handling the division cases, you would end up with code that looks like this -
    <?php // initialization // the error related settings should be in the php.ini on your system error_reporting(E_ALL); ini_set('display_errors', '1'); 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 if($_SERVER['REQUEST_METHOD'] === 'POST') { // inputs: number_entered, $_SESSION['answer'] // trim all the post data at once $post = array_map('trim',$_POST); // if any input is a array, use a recursive trim call-back function here instead of php's trim // validate inputs if($post['number_entered'] === '') { $errors['number_entered'] = 'You must enter a number'; } // note: this assumes that only integer answers are permitted (in the case of the division operator) else if((int)$post['number_entered'] !== (int)$_SESSION['answer']) { $errors['number_entered'] = "Incorrect guess<br>The correct<br>number was <b>{$_SESSION['answer']}</b> <br><img src='sorry-tryagain.png'><br>"; // since you are displaying the correct answer, you would want to generated a new question in this case? //unset($_SESSION['question']); } // if no errors, success if(empty($errors)) { $_SESSION['success_message'] = "<img src='you-win.png'><br><b>{$_SESSION['answer']}</b> IS THE<br>CORRECT GUESS!</b><br>"; // to continue, you would generated a new question //unset($_SESSION['question']); // 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 // if there's no question/answer, generate one if(!isset($_SESSION['question'])) { $rand1 = rand(0, 9); $rand2 = rand(0, 9); $operator = array('*', '/', '+', '-'); $randoperator = $operator[rand(0, 3)]; switch ($randoperator) { case "+": $finaalvalue = $rand1 + $rand2; break; case "-": $finaalvalue = $rand1 - $rand2; break; case "*": $finaalvalue = $rand1 * $rand2; break; case "/": // note: this can produce a fractional number, which you must take care with when performing comparisons. // also division by zero. $finaalvalue = $rand1 / $rand2; break; } $_SESSION['question'] = "$rand1 $randoperator $rand2 = "; $_SESSION['answer'] = $finaalvalue; } // html document - this is an incomplete document. it only shows the necessary parts for the demonstration. ?> <?php // display any success message if(isset($_SESSION['success_message'])) { echo $_SESSION['success_message']; unset($_SESSION['success_message']); } ?> <?php // display any errors if(!empty($errors)) { echo "<p>".implode('<br>',$errors)."</p>"; } ?> <?php // display the form if(!empty($_SESSION['question'])) { ?> <form method="POST"> <br><b>Level 1<br>Do The Math</b><br><br> <?=$_SESSION['question']?> <input type="text" name="number_entered" value="<?=htmlentities($post['number_entered']??'',ENT_QUOTES)?>" autocomplete="off"><br><br> <input class="button" type="submit" value="Enter Guess"><br><br> </form> <?php }  
  11. mac_gyver's post in Error fetching booked seats: SyntaxError: Unexpected token '<', "<br /> was marked as the answer   
    lol.
    all the javascript posted for this problem is unnecessary. upon the DOM being loaded/rendered, it's getting data that's known at the time of the request for the map2.php page (the value being sent to getBookedSeats.php is coming from a js variable that's being set to a php value echoed on the page.) this is just a roundabout wall of code and data churn.
    here's a list of why this is not working -
    1. you are making a POST request to getBookedSeats.php. the value won't be in any $_GET variable and adding an isset() won't make it work. all that did is hide the problem and caused the php code to be skipped over.
    2. you are sending JSON encoded data to getBookedSeats.php. you would need to use the following to read and decode the data -
    $json = file_get_contents('php://input'); $data = json_decode($json,true); 3. the value will then be in $data['screeningId'], because that's the name of the javascript variable holding the value that you are sending in the ajax fetch request, which is a value that is coming from php in the first place.
     
  12. mac_gyver's post in Pass variables from page to page was marked as the answer   
    each page must enforce what the current user can do and see on that page, for a non-logged in user, for a logged in user, and for a logged in administrator.
    if the current user is not logged in, they can only do and see what you have coded on that page for a non-logged in user to do and see. if they are a logged in user and the user ID in the URL is the same as the currently logged in user ID, they can perform actions like editing their own data and seeing all of their own data. if the currently logged in user is a administrator, he/she would be able to pick any user and be able to perform actions like editing that user's normal data and seeing all that user's normal data, and be able to edit/see additional data, such as permissions, edit history, site activity, ip history, ...
    if you aren't already doing so, your login code should store the user id (autoincrement primary index) in a session variable to indicate who the currently logged in user is. if there is a logged in user, you would query on each page request to get any other user data, such as - username, email, permissions, ...
  13. mac_gyver's post in I can't dynamically paginate with this php script was marked as the answer   
    you would need to use JSON.stringify({page:2}) for there to be a 'page' element in the decoded data.
  14. mac_gyver's post in trying to create new connections after each login using PDO was marked as the answer   
    the user registration/login system on your web site is for the purpose of determining what a user can see and do on the web pages. this has nothing to do with database connections. it is your application code that is performing the database operations and the database connection credentials are making a connection to allow your application code to do its work. it is up to your application code to determine what database operations can be performed for any user to your site.
    this is not how web applications are implemented. post or describe an example of something you think requires this, and a forum member will provide information on how to correctly implement it.
  15. mac_gyver's post in problem - spaces in an associative array values from $_POST[] variable was marked as the answer   
    a space in an attribute value is a stop character, indicating the end of the value. to make this work, you need to enclose the attribute value in quotes (single or double.) you should actually always enclose attribute values in quotes, for consistency, even in those cases where they are not required.
    however, the value attributes should be the organization ids, not the organization names, so that when you store the submitted data, you are storing the  organization id. this will result in the least amount of data storage, the fastest queries, and allow you to edit the organization name or even display the organization name in a different language, without affecting the stored data.
    next, for the 'required' attribute to work, the first option choice needs to have an empty value attribute and serve as a prompt, e.g. <option value=''>Select an Organization</option>.
    lastly, there's no good reason to catch and handle an exception from a SELECT query. any error from this type of query, is either due to a programming mistake or the database server is not running, is not recoverable by the user, and the user doesn't need to know anything about its occurrence. simply do nothing in this case and let php catch and handle any database exception from a SELECT query.
  16. mac_gyver's post in Multi-dimensional array issue. was marked as the answer   
    the reason to use the name as the array index is this allows you to directly test for and access the entry in the array, without needing to search through the entire array. this is the same reason that you index data in a database. this greatly simplifies and speeds up the code/query.
    the reason your code doesn't work when the data starts at the zeroth index in the array is because array_search() returns the index if the value is found, but the zero index is a false value in a loose-comparison. array_search() returns an exact false value when the search fails to match a value. to test for a not-found condition, you must test if the returned values is exactly false, e.g. ===false. to test for a found condition, you must if the returned value is not exactly false, e.g. !==false.
  17. mac_gyver's post in Data not showing properly in correct header was marked as the answer   
    the code is doing exactly what it was written to do, build a <tr><td>num</td></tr> for each number. if you want to produce a single <tr></tr>, you would need to add the opening <tr> before the start of the looping and add the closing </tr> after the end of the looping.
  18. 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.
  19. 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.
  20. 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.
  21. 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.
  22. 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?
  23. 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.
  24. 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.
  25. 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.
×
×
  • 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.