Jump to content

mac_gyver

Staff Alumni
  • Posts

    5,450
  • Joined

  • Days Won

    175

Everything posted by mac_gyver

  1. while you should keep the posted form data as an array and operate on elements of this array throughout the rest of the code. e.g. in the validation logic and the ->create() logic, what you are actually doing is decoding the json to an object, manually building an array from those properties, then manually setting the product class properties from the elements in that array. all of this typing for every field/column and copying properties/variables to other properties/variables is not necessary and is a waste of typing time. just set the 2nd parameter of json_decode() to a true value and you will directly end up with an array of data. next, related to item #1 in the list in my first post in this thread, user written classes/functions should be general-purpose and reusable. your class methods/properties should not contain any application specific values, code, queries, or html markup. they should instead do useful things that help you to produce applications. the way to make your code general-purpose is to use a data-driven design, where you have a data structure (array) that defines the fields/columns, display labels, validation rules, and type of processing each field is to be used for. you would use this defining data structure to control what the general-purpose code will do. this will eliminate all of the repetitive application specific typing you have in the current code. the 'status' => 200 value that you are putting into the json encoded data has nothing to do with the http status value that the ajax code uses for the success/error sections. the status value that the ajax code receives is something that the web server outputs as part of the response header. as already stated, the ->create() code needs to return a true value at the point that it determines that the insert query was successfully executed. it needs to return a false value when it determines that the insert query failed due to a duplicate index error number. the code that calls the ->create() method must test the returned value to determine what message to set up, json encode, and echo as the response. for a true returned value, you would setup the "Created Successfully" message. for a false returned value, if you only have one unique column, you would just setup a 'canned' message that the value submitted for that column is already in use. however, for what you are doing, the sku and the name columns must both be defined as unique indexes. the insert query will fail at the first duplicate index. you would like to tell the user all the columns that have duplicate values at once, so that they don't need to keep correcting and resubmitting the values one at a time. to do this you would execute a SELECT query for just the unique columns and setup a message for each column that contains a value matching the submitted form value in the result set. you would then output the resulting duplicate error message(s) in the json encoded response. the example code outlines what the post method form processing code should do. this would become part of the create.php code. since you are using ajax to submit the form data, you would only need the initialization and post method form processing sections from the example. the post method form processing would - detect that a post method form was submitted json_decode the json data to an array, that you would then use as the input data for the validation logic and supply as a call-time parameter to the ->create($data) method. trim all the elements in the data array at once. since this is an array, you can use php's array functions to operate on it, such as array_map() to apply php's trim function to all the elements in the array. validate all the elements in the array, storing validation errors in an array using the field name as the main array index. after all the validation logic, if there are no errors, the array holding the user/validation errors is empty, you would use the form data. it is at this point that you would call the ->create() method and test the returned value from that call. if the returned value is false, you would add the duplicate data messages to the array holding the user/validation errors. at the point near the end, where the - // if no errors, success comment is, is where you would build the $response array, with either a success message or the user/validation error messages, json encode it, and echo it.
  2. your ->create() method code doesn't return a specific value, so null is returned. since null is not a true boolean value, the conditional logic where you are calling that method executes the else {...} branch, which outputs 'message' => 'Product Not Created'. the ->create() method should return a true value upon success. a great point of using exceptions for errors is that your main/in-line code only 'sees' error free execution, since exaction transfers to the nearest correct type exception handler, or to php's exception handler if there's none in your code, upon an error. what this means is that if your code reaches the line after the ->execute() call, that the insert query was successful. it is at this point where you would return a true value. the .ajax error code is for if the ajax request fails, meaning that the http(s) request didn't work at all. this doesn't mean that the server-side operation failed. the .ajax success code will be executed if the ajax request works correctly. you must access the json data in the success code. see the example code in this post - https://forums.phpfreaks.com/topic/315403-saving-to-mysql-database-not-working/?do=findComment&comment=1601407
  3. you are deleting the comments without even reading and understanding what they say.
  4. you need to fix all the occurrences of short opening php tags. the occurrences in the form that isn't working are probably breaking the html markup and preventing the form fields from being recognized. you can check what the submitted form data is by adding the following near the top of the php code - echo '<pre>'; print_r($_POST); echo '</pre>'; by doing that, you prevented anyone here from directly helping and wasted the time of those that looked at the posted information. you have some sql related code in a html context, some form fields outside of any form, form data that you state work without existing in any of the posted code. if you want actual, direct help post all the code needed to reproduce the problem.
  5. updating old mysql_ based code requires more than just making it work. you must also make it secure. php's magic_quotes, which provided some protection against sql special characters in string data values from breaking the sql query syntax, which is how sql injection is accomplished, has also been removed. the best choice for updating old application code is to use the PDO extension and use prepared queries when supplying external, unknown, dynamic values to the query when it gets executed. since you must go through all the database specific code, you might as well future proof it by switching to the much simpler and more modern PDO database extension. if you use the PDO extension, when you make the connection, set the character set to match your database tables, set the error mode to use exceptions, set emulated prepared queries to false, and set the default fetch mode to assoc. for prepared queries, use simple positional ? place-holders and use implicit binding by supplying an array of input values to the ->execute([...]) call.
  6. 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 the post method form processing should - detect if a post method form was submitted keep all the input data in an array variable, then operate on elements in this array variable throughout the rest of the code trim all the inputs at once. after you do item #2 on this list, you can accomplish this with one line of code validate all the inputs, storing user/validation errors in an array using the field name as the array index after the end of all the validation logic, if the array holding the errors is empty, use the form data if an insert or update query can result in duplicate data, detect this in the error handling for the database query, and setup a message for the user telling them what was wrong with the data that they submitted after the end of the form processing logic, if there are no user/validation errors, perform a 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 the session variable at the appropriate location in the html document. if there are errors at item #5 or #7 on this list, the code will continue on to display the html document, redisplay the form, where you should populate the form field values/selects/checkboxes with any existing values so that the user doesn't need to keep reentering/selecting/checking data over and over. you should get your code to fully work first with one form field, then one field of each type, before you worry about all the code needed for all the rest of the fields. you can use the following to display what post data is being submitted to your code - echo '<pre>'; print_r($_POST); echo '</pre>'; the posted code contains a php syntax error on line #13. to get php to display syntax errors, you must set php's error_reporting to E_ALL and display_errors to ON, in the php.ini on your development system (putting these settings into your code won't work for php syntax errors since your code never runs to change the settings.) stop and start your web server to get any changes made to the php.ini to take effect and confirm that the settings actually got changed by using a phpinfo() statement in a .php script file. you should also validate any resulting web page at validator.w3.org to help make sure the markup is valid and you should only write markup that is necessary.
  7. putting the settings in your php code won't help with php parse errors in that file, which was one of the problems in this thread, since the code never runs to change the settings. putting these settings in the php.ini will cause ALL errors to be reported and displayed. it also allows you to change the settings at a single point, so you don't need to go through and edit your code when you move it to a live/public server, where you DON'T want to display all errors, you want to log them.
  8. php variables are not replaced with their value unless the string they are inside of uses initial/final double-quotes. also, when you have just a variable, e.g. the $dbuser and $dbpass, don't put quotes around it/them at all. several of the things you have posted should have been producing php errors. 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? the PDO extension is much simpler, more consistent, and more modern than the mysqli extension. if you are just starting out, forget about the mysqli extension. when you make the PDO connection, you should name the variable holding the connection as to what it is, such as $pdo. you should also set the character set to match your database tables, set the error mode to use exceptions, set emulated prepared queries to false, and set the default fetch mode to assoc. don't bother catching any database exception unless it is for something that the user to your site can recover from, such as when inserting/updating duplicate or out of range data. in all other cases, simply let php catch and handle any database exception, i.e. don't put any try/catch logic in your code. you should always list out the columns you are SELECTing in a query and build the sql query statement in a php variable. this is obsolete markup. use css instead. you should validate your resulting web pages at validator.w3.org don't copy variables to other variables for nothing. this is just a waste of typing. just use the original variables. in most cases, there's no need to free result sets, free prepared query handles, or close database connections, since php will destroy these when your script ends.
  9. the main point behind just attempting to insert the data and test for a unique index error, is because your database must enforce uniqueness. it is the last step in the process. when there are multiple concurrent requests to your current code, a race condition exists where all the instances will find from the SELECT query logic that the value doesn't exist. they will then all attempt to run the INSERT query, resulting in either duplicate data (if your column(s) are not defined as unique indexes), or the first query will win the race, with the others resulting in duplicate errors. since your database must enforce uniqueness, you might as will eliminate the initial SELECT query, since it isn't doing anything useful. as to why your current code with the SELECT query, which you are going to eliminate from the design, isn't finding if the value exists, is because php variables/class-properties are not replaced with their value when enclosed in over-all single-quoted strings. had you used a proper prepared query, which the first code at the top of this thread was doing, this problem wouldn't have occurred. also, the name column should be defined as a unique index as well, i.e. both the sku and name must be unique. client-side validation is a nicety for legitimate visitors. data submitted to your web site can come from anywhere, not just your code, can be anything, and cannot be trusted. you MUST trim (mainly so that you can detect if all white-space characters were entered), and validate the data on the server before using it.
  10. // before the start of the loop, set a variable to the unique/one-time output you want. $first = 'class="active"'; while($row = mysqli_fetch_array($result)) { // echo that variable at the point where you want the output ?> <li><a id="<?php echo $row["urlName"] ?>Tab" <?=$first?> href="#<?php echo $row["urlName"] ?>Content"><?php echo $row["title"] ?></a></li> <?php // then set that variable to an empty string after the point where you echo it. every pass through the loop after that point will echo an empty string, i.e. nothing will be output. $first = ''; }
  11. no. it's not more easy.
  12. before the start of the loop, set a variable to the unique/one-time output you want. echo that variable at the point where you want the output, then set that variable to an empty string after the point where you echo it. every pass through the loop after that point will echo an empty string, i.e. nothing will be output.
  13. in a copy of my original posted code, search for every place where $post exists and what related comments there are in the code. see where it is defined and initialized to an empty array? see where it is assigned a value from the array_map() call? see where elements of it are tested in the validation logic? see where elements of it are displayed in the form field value="..." attribute? do the same for the $errors variable. see where it is defined and initialized, elements of it are assigned a value in the validation logic, where it is tested after the end of the validation logic, and where it is tested and displayed in the html document? if you are not understanding and following how these two variables are being used throughout the code, you will not be able to do this activity.
  14. there shouldn't be else statements in the validation logic, unless they are for different validation steps for the same input, such as for the first name, where you should setup a specific message for each possible validation error telling the visitor what was wrong with the value they submitted. a required value that is empty, or it too long, or contains characters that are not permitted need three different error messages. validating independent/separate inputs is NOT mutually exclusive. you are to validate each input separately, storing any validation error in the $errors array using the field name as the array index. by using else statements, only the first validation error will get setup and displayed, requiring the user to resubmit the form over and over for each different validation error. also, by no longer trimming and keeping the form data as a set, in the $post array, none of the field value='...' attributes will get populated with the existing data upon an error. you are making syntax and logic changes where none is needed.
  15. you should be learning, developing, and debugging your code/queries on a localhost development system. trying to use public/online hosting is a waste of time, constantly uploading, and making sure there were no upload errors, to see the result of each change. until your code is secure, this opens the possibility of your web hosting getting abused by hackers. also, most cheap shared web hosts disable things like php's error related settings and database error settings that you need in order to get php and your database statements to help you. they also set disk and web server caching so that you won't immediately see the result of changes you make to your code. the database hostname on shared hosting is generally not going to be localhost. your web host should have an FAQ section that gives examples of connection credentials. the control panel where you created your database user/password should also list the hostname/ip address to use and any prefix for the username. if you can setup php's error related settings, you need to set error_reporting to E_ALL and set display_errors to ON. these should be in the php.ini on your system so that they can be changed at a single point. next, you always need error handling for statements that can fail. for database statements that can fail - connection, query, prepare, and execute, the simplest way of adding error handling, without adding logic at each statements, 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 above paragraph) to control what happens with the actual error information (database statement errors will 'automatically' get displayed/logged the same as php errors.) to set the error mode to exceptions 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); lastly, if you are just starting with php/MySql, learn and use the simpler and more modern PDO database extension.
  16. the catching of the database statement error would be in the server-side code, where you would detect if the error number is for a duplicate index error, and setup a message telling the user what was wrong with the data that they submitted, which in this case would be that the sku already exists. here's the whole story - you always need error handling for statements that can fail. for database statements that can fail - connection, query, prepare, and execute, the simplest way of adding error handling, without adding 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 to control what happens with the actual error information (database statement errors will 'automatically' get displayed/logged the same as php errors.) the exception to this rule is when inserting/updating duplicate or out of range user submitted data values, which are the only kind of database errors that the 'user' on your site can recover from (all other database errors are either due to programming mistakes, the database server not running, or nefarious activity, that the user doesn't need to know anything at all about), by potentially entering new value(s) and resubmitting the data. in these cases, your code would catch the exception, test if the error number is for something that your code is responsible for handling, and setup a message for the user letting them 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. you would set the PDO error mode to exceptions when you make the connection. the net result of submitting the form data to the server-side code for this Create/insert operation should be either a success value/message or failure message(s) - consisting of all the user/validation errors. since you are making an ajax request, you should create an array with a 'success' or 'error' key, with the appropriate values, json_encode() this and output it to the browser for the ajax success code to test and use. some points about the posted code - OOP is not about wrapping a class definitions around parts of your main code and adding $var-> in front of everything to get it to work. all this is doing is exchanging one defining/calling syntax for another one, taking 2-3 times the amount of typing to accomplish a task. you won't be using a SELECT query anymore for this current operation, but when you do use a select query, list out the columns you are selecting. for cases where you just need a count of the number of matching rows, use a SELECT COUNT(*) ... query, then fetch and use the count value. related to this, the rowCount() method may not work for a data retrieval query for all database types, and should be avoided for these type of queries. you should always fetch all the data that a query returns (the current code should be producing an out of sync error since you didn't fetch the row(s) of data from the select query.) also, for a select query, the only variable name that must be unique is the final variable holding the data fetched from the query. just use simple names like $sql, $stmt, ... for the variables in the common code. writing out variables/properties by themselves does nothing (doesn't even produce any php byte code.) why do you have those 9 lines in there? if you use simple positional ? place-holders and implicit binding, by supplying an array to the ->execute([...]) call, it will save a ton of repetitive typing and typo mistakes. any php error related settings should be in the php.ini on your system so that they can be changed at a single point. having a display_errors setting inside some conditional logic in your code makes no sense.
  17. the getLocationInfoByIp() function call is returning a boolean (probably a false value), so the array dereferencing of the returned value, e.g. the ['country'] element, is also failing. you would need to determine why the function call is failing. you also always need error handling for statements that can fail so that your code doesn't attempt to use non-existent data.
  18. <script> const format = (num) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(num); </script> replace $('#totalPrice').text(totalPrice); with $('#totalPrice').text(format(totalPrice));
  19. the comma thousands separator is a display convention that makes a number human friendly. it has no meaning to a computer and actually breaks the value. you are calculating and displaying a value in the browser. you must format that number in the browser when you display it. i hope you are not planning on using the price from this hidden field, as it can be set to anything, such as .01, in the submitted data. only the id and the quantity should be submitted.
  20. the ->execute() syntax is a method/function call. the () are part of that syntax. it takes an array as the call-time parameter. the example code i posted only needed to have each additional field added to the validation logic, the sql query, and the array of parameters in the ->execute() call. this is a simple A-B pattern matching exercise.
  21. the ->execute() method call accepts an array of values that correspond to the ? place-holders in the sql query. The [ and ] you are asking about are php's array definition syntax. the single $post['fname'] variable is a single value/element within that array. to supply more than one value, you supply more than one variable within that array. if $post['fname'] is one variable and $post['lname'] is another variable, wouldn't that look like [ $post['fname'], $post['lname'] ]
  22. all the code needed to search for data already exists. it is called a database engine. unless this is an assignment that requires you to store the data in a file, save yourself the trouble of redesigning a proverbial wheel again and just use a database. your search form and form processing code should be on the same page, this results in the most secure code, the best user experience, and the simplest code. your search form should use method='get', this is a convention used on the www, where if someone finds a result they want, they can book-mark the url or share the url with others and be able to return to the same result. your search form should be 'sticky' and repopulate the field values with any existing data, this serves to both display the search term and allows the user to modify the search simply by modifying any of the field value(s). once the search form has been submitted, except for unchecked checkbox/radio fields, all the fields will be set, i.e. don't use isset() for every always-set field. if you are selecting from existing data values, rather than free typing values, which should use a wild-card match, you should use a select/option menu. the code on any page should be laid out in this general order - initialization post method form processing - used when performing an action on the server, such as inserting, updating, or deleting data get method business logic - get/produce data needed to display the page. any code that knows how to query for and fetch data goes here... html document regardless of the data source - database, api that returns json encoded data, a file, the code that knows how to query for and fetch the data belongs in section #3. the output from this code should be an array, that's either empty, if no matching data was found, or an array of rows of the matching data. simple php code in the html document will just test/loop over this array of data to produce the output. your form processing code should trim, then validate all inputs before using them. if a required field is an empty string after being trimmed, that's an error. you should setup a message for the user telling them what was wrong with the data that they submitted, and not attempt to use the input data at all. if you want your query code to return all data when there is no search input, you will need to write logic to specifically do this. if you are going to use a file to hold the data, you need to use file locking and have file error handling so that concurrent access to the file won't corrupt the data stored in the file. if you use a database for this, the database engine will take care of any locking needed for concurrent access. after you explode the data you read from the file, you should trim each resulting element, i.e. don't assume that your file will always have exactly the white-space shown. array_map(), using either one of php's built-in functions or a user written call-back function is useful for operating on data stored in arrays. you could for example write a call-back function to take the result of the file() call, explode, trim, and build associative indexed arrays for each line read from the file. the reason why it was suggested to get your code to work for one form field, which could initially be any of the fields, is you need to get your code to work at all, with just one field, before you can worry about all the code needed for the other fields.
  23. re: your last post above. if you are seeing the form, given that there are php syntax errors still present, it is likely that you are not requesting the page using a url -
  24. your posted connection code works for me, so it probably isn't being executed at all. what output do you get? and if it's a blank page, what does the 'view source' in your browser show? are you requesting your main page using a URL to the web server on your development system? the url should be similar to - http://localhost/your_main_file.php NOT something like file:///C:/xampp/htdocs/your_main_file.php, which is a file system path and doesn't cause the php code to be executed. your first posted code contains a number of php syntax errors that will prevent it from running at all. until you actually do item #1 on my list, php will not help you with php syntax errors in all your files because putting the php error related settings in a file won't cause the settings to take effect because the code in that file doesn't run when there's a php syntax error in that file. beyond the above points, you would need to post your current code to get any help with it. if you incorporate all the practices listed, which are designed to make your code secure, in all contexts, provide a good User eXperience (UX), by letting the user know when they did something that they can correct and prevent them from having to keep retyping information over and over, result in simple general-purpose code, that doesn't have you typing a bunch unnecessary things that don't contribute to a working application, through the php error related settings (item #1 in my list), the validation logic (item #6), and having error handling (item #9), your code will either work or it will tell you why it isn't. here's an example showing all the posted points - <?php // initialization session_start(); // why not have the connection code actually make the connection too, so that you don't need another line of code? require "conn/connect_seniorform.php"; // note: this code uses the much simpler and more modern PDO database extension // when you make the connection - // set the character set to match your database tables, so that no character conversion occurs over the connection // set the error mode to use exceptions, so that all the database statements will use exceptions (this is the default now in php8, but set it anyways) // set emulated prepared queries to false, you want to run real prepared queries // set the default fetch mode to assoc, so that you don't need to specify it in each fetch statement $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: first_name (add others once code is working) // trim all the input 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 all inputs // first name if($post['first_name'] === '') { $errors['first_name'] = "First Name is required"; } // validate other inputs here... // if no errors, use the input data if(empty($errors)) { $sql = "INSERT INTO senior_dat (first_name) VALUES (?)"; $stmt = $pdo->prepare($sql); // note: the following try/catch error handling deals with having a (single) unique column (email) defined in your database table // if you have multiple unique columns defined, you would execute a SELECT query inside the catch code to find which column(s) contain duplicate values matching the input data and setup an error message for each one try { // a 'local' try/catch to handle a specific error type $stmt->execute([ $post['first_name'], ]); } catch (PDOException $e) { if($e->errorInfo[1] == 1062) // duplicate key error number { $errors['email'] = "Email is already in use"; } else { throw $e; // re-throw the pdoexception if not handled by this logic } } } // if no errors, success if(empty($errors)) { $_SESSION['success_message'] = "Form saved OK"; die(header("Refresh:0")); } } // hrml document starts here... ?> <?php // display and clear any success message if(!empty($_SESSION['success_message'])) { echo "<p>{$_SESSION['success_message']}</p>"; unset($_SESSION['success_message']); } ?> <h1>SENIOR RENEWAL FORM</h1> <?php // display any errors if(!empty($errors)) { echo '<p>'; echo implode('<br>',$errors); echo '</p>'; } ?> <form method="post"> <label><b>First Name:</b><br><input type="text" name="first_name" size="20" maxlength="40" value="<?=htmlentities($post['first_name']??'',ENT_QUOTES)?>"></label> <br> <input type="submit" value="submit"> </form> if you insist on using the overly complicated and inconsistent mysqli database extension, adding the following line of code, before the point where you make the database connection, will cause it to use exceptions for errors (item #9 on my list) - mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
×
×
  • 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.