Jump to content

mac_gyver

Staff Alumni
  • Posts

    5,450
  • Joined

  • Days Won

    175

Everything posted by mac_gyver

  1. the error about an undefined variable is the same problem at the start of your thread in a different help forum. php class methods have local variable scope. if the logic class is truly dependent on the data class, you would use dependency injection to make the instance of the data class available in the logic class. however, i doubt that is actually what you are trying to do. you need to post all the relevant code in order to get the best solution. based on the names you have given your classes, you have taken the data and processing for a task and surrounded each of them with class definitions. this is not OOP. OOP is not about doing a bunch of typing adding a bunch of defining and calling syntax, then adding $var-> or $this-> in front of everything in order to make it work. all this is doing is wasting time adding a layer to your code that adds no value to that you are doing.
  2. and what exactly was the output that you got from those statements?
  3. yes. you would create one page that accepts a $_GET variable as an input. you would test if the variables is set (see isset()), trim, validate that the value is an integer greater than zero, then securely use the value in an sql query to get the matching data to display on the page.
  4. pagination involves two sql queries. the first one gets the total number of matching rows (including any join, where, or having terms), so that you can calculate the total number of pages, used when looping to produce pagination links and to test/limit the requested page number. the second one adds a limit term to the base query to get the requested page of data. it doesn't matter what your presentation code is doing with the data that it loops over. you are just producing some output for each pass through the loop. you should actually remove the database specific code from the html document, put it above the start of the html document, then fetch the data that the query matches into an appropriately named php variable. you would then test/loop over this variable where the database specific code is currently at in your html document.
  5. It's possible that some of the data values that are not present for a one-way trip don't have an acceptable default value and/or are not allowed to be a null value in the database table definition, and the database server mode is now set to strict mode, which will cause an error for those columns, rather than truncating data to the nearest min/max value. this code doesn't have any (useful) error handling for the database statements that can fail and the one place it does have some, won't work, because the connection variable is missing from the msyqli_error(...) call. the easiest way of adding error handling for all the database statements, without adding logic at each statement, is to use exceptions for database statement errors and in most cases 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 get displayed/logged the same as php errors.) to use exceptions for errors for the mysqli extension, add the following line of code before the point where you make the one/single/first connection - mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); i hope that this code is just part of an assignment and is not on a live/public server, because it has no protection against sql special characters in the data values from breaking the sql query syntax, which is how sql injection is accomplished. you should be using prepared queries when supplying external, unknown, dynamic values to a query when it gets executed.
  6. this is a lot of unnecessary typing, processing, and evaluating the count() inside the loop statement is the slowest way to do this, just to convert an array of objects to an array of arrays (presumably you are doing something with $post_data on each pass through the loop) and to format the date/time. just originally fetch the data as an array of arrays, not of objects, and either format the date/time in the query or as a one-time operation on the fetched data.
  7. no. the code using mysqli_fetch_xxxx statement is fetching a row of data from the result of the query, as an associative, a numeric array, or both (default is both), assigning the fetched row of data to the $row variable, then the while() conditional/loop statement is testing the true/false result from that fetch/assignment. this stops because when there is no more data to fetch, a false value is returned by the fetch statement. the while loop code works because the condition being tested changes from true to false when the end of the data is reached. the while loop code you proposed is assigning the whole array in $this->data() to $obj, each pass through the loop, which is always a true value for a non-empty array, so, the loop becomes a forever-loop. while (pun intended) you can make a while() loop loop over an array, the php function needed to do so has been removed in php8, i.e. there's no good reason to change from using a foreach() loop to loop over an array of data. what problem are you having by using a foeach loop that you are trying to solve?
  8. these functions have multiple false return points, each with a different cause. to debug this, wouldn't you need to determine (display/log) which conditional branch has failed? you need to write a debugging function, that you can add to various points in the code, that will either display/log, depending on the value of a DISPLAY_DEBUG (or similarly named) defined constant, useful and unique information about each failure point. this code also has inconsistent error handling for the database statements that can fail - prepare() and execute() (yes an execute call can fail due to an error, such as when a hacker submits data exceeding the max packet size between php and the database server.) for some of the prepare failures, you do nothing, which would cause the function to return a null value and in another case you are explicitly returning a false value, meaning that the login failed. rather than to add error handling logic for those cases where it is missing and fix the one case that does exist, just use exceptions for database statement errors and in most cases 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 the existing database error handling logic since it will no longer get executed upon an error, simplifying your code. the exception to this rule is when inserting/updating duplicate or out of range user submitted data (which you are not doing in the code posted in this thread.) in this case, your code would catch the exception, test if the error number is for something your code is supposed to handle, then setup an error message for the user telling then what was wrong with the data that they submitted. for all other error numbers, just rethrow the exception and let php handle it as already described. 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);
  9. to define what quantities are/are-not available, for each item, you need an item_carton table - id, item_id, quantity, any other useful status/flag columns. there can be cases where there is more than one carton size for an item, i.e. 15, 25, either concurrently or as time passes. there can also be cases where a unit item cannot be bought, only a full carton. you would assume that unit items can be bought, unless overridden by an entry in this table. you would also need a status flag, somewhere, indicating if the available quantity is limited to the stock on hand, i.e. more of the item cannot be obtained. if an item has an entry with this flag set, you could query to get the available quantity and display it on the item add to cart page as the maximum quantity available. for your example, there would be a row with the noodle item_id and quantity 15 to indicate that a carton quantity of 15 is available for that item. the lack of a row indicating that unit items cannot be bought would indicate that unit items are available. when you search and list items on the add to cart page, you would left join the item table with the item_carton table to determine what can/can-not be bought for each item. for your example, you would list that single items and cartons with quantity 15 can be bought. you would need an inventory table that would have a row inserted for every transaction that affects the inventory of an item. to handle both carton and unit items, in addition to item_id and quantity columns, you would have an item_carton_id column (an id from the above item_carton table.) if this column contains a value, it indicates the row is for a carton and the quantity is the number of cartons. if this column does not contain a value, the quantity is the number of unit items. for your example, when the 30 cartons were received, a row with the noodle item_id, 30 for the quantity, and the corresponding item_carton_id from the item_carton table would be inserted. when the cart is finalized and converted to an order, you would insert a row into an order table, with the unique/one time order information, establishing an order id, and insert row(s) for the carton/unit items into an order_item table. the order_item table would have an item_carton_id column, the same as defined for the inventory table (you will end up doing a UNION query between the two tables to determine the current carton/unit quantity of item(s)). to determine if a full case needs to be opened and broken into unit items, you would then query to find the current unit quantity for the item id that was just inserted. if it is a negative value, you would then insert a row into the inventory table that deducts enough full case(s) and insert a row into the inventory table that adds that many case quantity of unit items. for your example, when the order is submitted, you would insert a row for one carton and two unit items into the order_item table. since there are initially no unit items in the inventory, the above logic would get a negative 2, determine that this requires one carton to be broken into unit items, insert a row to deduct one full carton from the inventory, and insert a row with 15 unit items into the inventory table.
  10. is the partID column value unique? if it is, there's no point in looping to produce the form fields. if it is not, you would need to use array names for the form fields and use some unique id as the field indexes so that you can update more than one row of data. does your form have partUpdate and partID fields so that the php code will do anything? always validate input data before using it ($_GET['partEdit']) and don't put external, unknown, dynamic values directly into an sql query statement. if you did this for the SELECT query because of how hard it is to use the mysqli extension for a prepared query, switch to the much simpler PDO extension. do not pass unnecessary values through a form since all external data can be set to anything and cannot be trusted. query inside the form processing code to get the existing/old values. your post method form processing code must detect if a post method form was submitted before referencing any of the form data. next, if the total size of the submitted form data exceeds the post_max_size setting, both the $_POST and $_FILES arrays will be empty. you must detect this and setup a message for the user telling them that the form data was too large and could not be processed. after you have determined that there is data in $_FILES, you must test the ['error'] element to find out if the file was successfully uploaded or not. the current test of the ['name'] element is not sufficient, i.e. some of the possible upload errors will have a non-empty name, but there is no file to save. only if the ['error'] element is a zero (UPLOAD_ERR_OK) can you actually use the uploaded file information. if it's a 4 (UPLOAD_ERR_NO_FILE), it would mean that no image was selected to be uploaded. for the other error values that the user has control over, you would setup a message telling them what was wrong. for the error values that the user has no control over, you would setup a general failure message, and log the actual information about what error occurred. lastly, you ALWAYS need error handling for all statements that can fail. for database statements, the easiest way of adding error handling, without adding logic at each statement that can fail - connection, query, prepare, and execute, is to use exceptions for errors and in most cases let php catch and handle the exception, where php will use its error related settings to control what happens with the actual error information, via an uncaught exception error (database statement errors will 'automatically' get displayed/logged the same as php errors.)
  11. how do you know that? one possible reason for not seeing your connection error message, for the case of intentionally invalid connection credentials, is that your php code is not being executed, perhaps due to being directly opened as a file in the browser instead of being requested via a url on your web server. another possibility is that where you are trying to create the connection is inside of some html markup where any output from your code/php won't be seen unless you look at the 'view source' of the page in your browser (you should do any initialization like this, or any main php business logic, above the start of the html document so that you won't have an issue with things not being seen on a web page.)
  12. or you can just use a database and write a simple sql query to find and retrieve the data that you want.
  13. it's not exactly the same. when there are php variables inside of a string, the type of quotes around the string matter. double-quotes are required to get the php variables to be replaced with their values.
  14. stock/inventory should be handled using an accounting/transaction ledger type system, where a separate row is inserted for every +/- transaction that affects a value. this will provide you with an audit trail so that you can tell if a programming mistake, duplicate submission, or nefarious activity has altered a value. you would then query to SUM() the +/- amounts for each item id to get the current stock/inventory amounts. when you submit the items making up an order/sale, you would insert a row into an order/sale table, with the unique/one-time information about the order. you would then get the last insert id from that query and use it when inserting the rows containing the item id/quantity into an order_item table.
  15. there's no need to compare, in php code, the column value fetched from the query with the column value being tested in the where clause. if the query matched a row(s) of data, the where clause was true. next, if you are not actually using the row(s) of data that a query matches, i.e. you are only testing if a value exists or how many times it exists, use SELECT COUNT(*) ..., and if this is for a 'registration' script, where you are deciding if you are going to insert a row of data, instead, just define that column as a unique index, attempt to insert the data, then test if the query produced a duplicate error. lastly, if you switch to the much simpler PDO database extension, a majority of the lines of code will go away.
  16. an ->execute() call can fail due to something wrong with the data being supplied to the query. what's your error handling for that case? i also see you edited a post above to add the code for the addComment method. you are using a prepared query. do NOT also use mysqli_real_escape_string on the data. this will result in the actual escape characters \ being inserted into the database, which will prevent searches from matching data. the main point of using a prepared query is to protect against sql special characters from breaking the sql query syntax, for all data types, not just strings. i also see you are applying nl2br to the input data. this is an OUTPUT function. it is used when you output data in a html context. do NOT use it on input data being stored in a database.
  17. here's an outline of what the code you are showing us should/should-not do - put any php error_reporting and display_errors settings in the php.ini on your system. this will let you make changes to these settings in one place and simplify your code. use 'require', not 'include', for things that your code must have for it to work. also, require/include are not functions and the () around the filename are not needed, simplifying your code. don't write code that isn't being used. in the current code, there are no session variables nor any user written functions. remove the session_start() and include("functions.php"); line, i.e. keep your code simple and uncluttered. the mysqli_report(...) statement should be before the point where you make the database connection, which you were also told in a previous thread on this forum. because the mysqli_report(...) statement causes the connection, query, prepare, and execute database statements to use exceptions for errors, the error handling logic you have now won't ever be executed upon an error, and should be removed, simplifying your code. the post method form processing code should detect if a post method form was submitted before referencing any of the form data. in your previous thread on this forum, you were doing this. why have you now changed from a simple statement to the mess of if()/isset() ... statements and why are you now using both $_POST and $_REQUEST variables? just use $_POST if you expect the data to be from a post method form. keep the input data as an array and operate on elements of this array throughout the rest of the code, i.e. don't write out line after line of code needlessly copying variables to other variables, simplifying your code. the post method form processing code should trim, then validate all the inputs, storing user/validation error messages in an array using the field name as the array index. after all the validation logic, if there are no errors (the array holding the user/validation error messages will be empty), use the submitted form data. if there are errors, you would display the contents of the errors array when you re-display the form. also in that previous thread, member(s) stated to use a prepared query to safely supply data to a query and to use the (much simpler) PDO extension. a prepared query, provided you use the PDO extension, only adds one php statement per query, allows you to eliminate any _escape_string() statements, and simplifies your sql query syntax, helping to prevent mistakes. after successfully completing all the post method form processing code, you should 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 re-submit the form data if the user reloads the page or browses back to the url of the page. in most cases, there's no need to close database connections, free query results, or free prepared query statements, since php will destroy all resources used on a page when your script ends, simplifying your code. you will notice a theme in the above of simplifying the code/query. there's a lot of old information to be found in books, course material, and on the web that is no longer needed. the following is a pseudo code example showing these points - <?php // use the much simpler PDO extension require 'pdo_connection.php'; $post = []; // an array to hold a trimmed working copy of the form data $errors = []; // an array to hold user/validation error messages // post method form processing if($_SERVER['REQUEST_METHOD'] == 'POST') { // trim all the form data at once (if any of the form fields are arrays, write and use a recursive trim function here instead of php's trim) $post = array_map('trim',$_POST); // validate the inputs here... // if no errors, use the form data if(empty($errors)) { // build the sql query statement, using a prepared query $query = " the sql query "; // prepare and execute the query // note: the following uses the PDO extension $stmt = $pdo->prepare($query); $stmt->execute([ an array of the input values ]); // note: an insert/update query may result in duplicate data. if this is an error condition // for your application you would define an appropriate unique index for your database table // then you would have exception try/catch logic for this query to detect if a duplicate // error number occurred and setup and display a message (add it to the $errors array) // telling the user what was wrong with the data that they submitted. for all other error // numbers just re-throw the exception and let php handle it } // if no errors, success if(empty($errors)) { // redirect to the exact same url of this page to cause a get request - Post, Redirect, Get (PRG.) header("Refresh:0"); die; } } ?> <?php // at the appropriate point in the html document, test and display any errors if(!empty($errors)) { echo implode('<br>',$errors); } ?> <?php // you would re-populate the form field values with any existing data so that the user doesn't need to keep reentering things over and over ?>
  18. you can use a phpinfo() statement in a .php script to check what the master and local values are for those settings.
  19. if you successfully set the php error related settings to the stated values, you should have gotten a http 500 error page. either they didn't get set to those values or you have settings in your code that are changing the values. a visitor to your site doesn't need to know anything about why a web page is not working and if you let a hacker know anything about what type of error occurred, they will just do more of the same to trigger more errors. you are logging the raw php/database error information on a live/public site so that you, the programmer/developer, will know what type of errors are occurring, so that you can find and fix what's causing them, or in the case of a database server not running, why the site was temporarily not working.
  20. yes. if you have access to the database server, you can temporarily stop it to test what the result will be. if you don't have access to the database server, temporarily introduce a typo mistake in the DB_SERVER value to test what the result will be.
  21. php's error_reporting setting should always be set to E_ALL (or even better a -1 since php has been confused about what the word all means.) on a development system, the display_errors setting should be set to ON. on a live/public server, display_errors should be set to OFF and log_errors should be set to ON.
  22. on a live/public server, you should log all php errors, which since you are using exceptions for the mysqli statement errors, will include the database statement errors. also, since you are using exceptions for mysqli statement errors, there's no point in having discrete logic to test for errors. that logic won't ever get executed upon an error, since execution transfers to the nearest correct type of exception handling, which will be php in the case of the code you posted. remove any such discrete error handling logic, simplifying your code. you should only display all php errors, when learning, developing, and debugging code/query(ies). put any php error related settings in the php.ini on your system, so that they can be changed at a single point.
  23. the session_start() in the messages.php file is probably failing, due to the html markup you are outputting on the register.php page, before the point where you are requiring messages.php. if you set php's error_reporting to E_ALL and display_errors to ON, you should find the actual reason for the code not working. the reason this works on your development system and not on the live server is most likely due to the output_buffering setting, in the php.ini, being set to on (a non-zero integer value) on your development system. you can check both systems using a phpinfo() statement in a .php script file to confirm this. since you may not be able to change this setting on the live server, it will be best if you turn this setting off on your development system, so that any code you produce won't stop, due to this problem, when you move it to a live server. in general, the code for any page should be laid out in this order - initialization post method form processing get method business logic - get/produce data needed for the dynamic content on the page html document your page should have one session_start() statement, it should either be directly or indirectly (via a required file) in the initialization section. item #2 means that your form processing code should be on the same page as the form. this will simplify all the code and provide a better User eXperience (UX), since you can re-populate the relevant form field values when you display any validation/user error messages and re-display the form. btw - you should NOT let the user know if a database or any other internal error has occurred. this information is only useful to you, the programmer/developer. you should display errors like this when you are learning, developing, and debugging code/query(ies) and log this information when on a live server. here's some additional points for the database connection code - name the connection variable $pdo or similar so that anyone looking at the code will know what it contains. set the character set to match your database table(s.) set the error mode to exceptions. the connection always uses an exception for errors, you want to the other database statements - query, prepare, and execute, to do the same, so that you don't need to write out a bunch of program logic to handle errors. 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 keep specifying it in every fetch statement.
  24. most of the points will actually simplify the code e.g. putting the form processing and the form(s) on the same page will eliminate all those lines of code for the session variables. the only increase in code are for things that don't exist now that the code needs. i thought of two more things that could cause the code/query(ies) to work on one server but not another and you might not get any indication from the current code/configuration as to what the problem is - this has to do with the output_buffering setting (if it's on, turn it off) and using the procedural mysqli statements. the error response for the procedural mysqli statements is different from the OOP mysqli statements. things that would be a fatal runtime error, if using OOP, halting program execution, are just warnings, if using procedural statements, and the code will continue to run, which if output_buffering is on, will discard the php warning messages. this has to do with the database server's strict mode setting and having no error handling for the execute() calls. if strict mode is set to ON, on the cheep/free hosting, out of range values will produce an error, but since there's currently no error handling for the execute() call, you don't know if this is happening or not. using exceptions for errors will solve this since it will give you error handling for all the database statements that can fail. if strict mode is off, on your development system, out of range values will instead be truncated to the nearest legal value for the data type, without producing an error. i didn't state it previously, but switching to the much simpler, more consistent, and better designed PDO extension will also simplify the code.
  25. there are a fairly large number of things that can cause your code to work on one system but not another and if your code is lacking validation and error handling logic, your code won't tell you why it is failing. under perfect conditions, on your development system, your code may work, but if anything goes wrong, you won't get any help from your code. firstly, you need to temporarily set php's error_reporting to E_ALL and set display_errors to ON, so that you will get immediate feedback if any php errors are occurring (the cheep/free web hosts may not allow you to do this.) you also need consistent and useful error handling for all the database statements that can fail - connection, query, prepare, and execute (which you don't currently have any error handling for.) the simplest way of adding error handling for all the database statements is to use exceptions for errors and in most cases 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.) this will let you remove the existing error handling logic and skip adding it where there is none. the exception to letting php catch the exceptions is when inserting/updating duplicate or out of range user submitted values, which is what you should be doing to detect if a product is already in the cart. in this case, your code should catch the exception, detect if the error number is for something that your code is designed to handle, then setup and display a message for the user telling them what was wrong with the data that they submitted. for all other error numbers, simply re-throw the exception and let php handle it. it doesn't appear that you have any validation logic? you should always trim, then validate all input data before using it. if there are no validation errors, use the submitted data. if there are validation errors, display them when you re-display the add product form(s). the only product information you insert into the cart is the product id and the quantity. all the other product data exists in the featuredlist table and should not be duplicated in the cart. you have a lot of unnecessary code that isn't helping. by putting the form processing code on a different page from the add product form(s), you have more code, a bunch of redirects, and are producing a bad user experience. when you put these on the same page, there will be less code, you can eliminate all but one redirect (upon successful completion), and you can display any validation/user error messages when you re-display the add product form(s). the only redirect you should have in your post method form processing code is upon successful completion of the processing code and it should be to the exact same url of the current page. this will cause a get request for that page. if you want the user to be able to navigate to other pages, provide navigation links. if you want to display a one-time success message, store it in a session variable, then test, display, and clear the session variable at the appropriate location in the html document. as to another reason why your code may not work, on one system, but not another, and be giving the symptom of going back to the cart.html page - what does using a phpinfo() statement in a php script show for the output_buffering setting? because you are redirecting all over the place (which hopefully you will remove, see the above paragraph), any debugging output from your script and any non-fatal php errors will get discarded if the ouput_buffering setting is ON (any non-zero value.) you should set this to OFF. lastly, you should not attempt to SELECT data in order to decide if it already exists. you should set up the table with a unique composite index for the column(s) that identify the user id and product id combination, just attempt to insert the data, and detect if a duplicate index error occurred (see the above paragraph concerning catching an exception for a duplicate 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.