Jump to content

mac_gyver

Staff Alumni
  • Posts

    5,341
  • Joined

  • Days Won

    173

Everything posted by mac_gyver

  1. 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.
  2. 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.
  3. you can also use the BC math functions, which expects strings as input and operates on each character as a bcd digit, like a hand held calculator works.
  4. instead of doing math, just explode the string on the '.' character, fill the cents part to two places with trailing '0' characters, and concatenate the two pieces together.
  5. 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.
  6. programming is an exact science. when you have a whole web page that doesn't work, you need to post all the actual code, less any database connection credentials, necessary to reproduce the problem. there could be a dozen different things wrong that could cause this symptom. we need to see what your actual code is in order to concentrate on what the code is or is not doing correctly.
  7. this is because as of php8 the mysqli (and PDO) extension uses exceptions for all database statement errors, by default, and execution transferred to the nearest correct type of exception handling (try/catch logic) in your code or to php's exception handling if there is no correct type of exception handling in your code, and all your code after the point where an exception occurred is not executed. a great point of using exceptions is that your main/inline code only 'sees' error free execution. if execution continues past a statement that throws an exception, you know that there was no error, without needing logic in your code to test if there was or was not an error. this lets you eliminate all the existing conditional logic in your code testing for connection and query errors, since it won't ever get executed upon an error, simplifying the code. because you didn't get any error indication at all, that means that php's error related settings are not set up on your system so that php will help you by reporting and displaying all the errors it detects. php's error_reporting should always be set to E_ALL and when learning, developing, and debugging code/query(ies), display_errors should be set to ON. when running code on a live/public server, display_errors should be set to OFF and log_errors should be set to ON. these settings should be in the php.ini on your system so that they can be set or changed at a single point. stop and start your web server to get any changes to the php.ini to take effect and check using a phpinfo() statement in a .php script file that the settings actually go changed to the desired values. the only time you should catch and handle a database exception in your code is for user recoverable errors, such as when inserting/updating duplicate user submitted data, which is something you are/should be doing. at a minimum, the email database column should be defined as a unique index. you would then have exception try/catch logic in your code around at least the execute() statement, check in the catch block if the error number is for a duplicate index error, and setup a message for the user that the email is already in use. for all other error numbers, just re-throw the exception and let php handle it. and if that wasn't enough, here's a list of practices, most of which will simplify the code - the form and form processing code should be on the same page. 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 code should only test if the request method == 'POST'. this is because there are cases where the submit button won't be set. you should keep the form data as a set, in a php array variable, then operate on elements in this array variable throughout the rest of the code, i.e. don't write out line after line of code that copies variables to other variables for nothing. you should trim all user entered data, mainly so that you can detect if it was all white-space characters, before validating it. after you do item #3 on this list, you can trim all the data using one single line of code. you should validate all input data, on the server, before using it, storing user/validation errors in an array using the field name as the main array index. except for unchecked checkbox/radio fields, all form fields will be set once the form has been submitted. there's no good reason to have isset() statements for always-set fields, and in fact doing so hides typo mistakes. as @Barand has already pointed out, you should be using a prepared query and switch to the much simpler and more modern PDO extension. after successfully processing the form data, you should execute a redirect to the exact same URL of the current page to cause a get request for that page. this will prevent the browser from trying to resubmit the form data should that page get reloaded or browsed away from and back to. if you want to display a one-time success message, store it in a session variable, then test, display, and clear that session variable at the appropriate location in the html document. to get a form to submit to the same page it is on, leave out the entire action attribute. if you put the closing </label> tag after the form field it corresponds to, you can leave out the for and matching id attributes, simplifying the code and eliminate a source of typos. in the name form field, your for attribute doesn't match the id attribute. the closing / in tags is no longer used. you need to validate the resulting web pages at validator.w3.org the form should be 'sticky' and repopulate the form fields with any existing values/choices so that the user doesn't need to keep reentering data over and over upon an error. any dynamic value you output in a html context should have htmlentities() applied to it to help prevent cross site scripting.
  8. to convert old mysql_ based code, you need to 1) convert the database extension to a currently supported one, 2) provide protection against sql special characters in a value being able to break the sql query syntax, which is how sql injection is accomplished, and 3) handle database statement errors. for item #1, the PDO extension is much simpler and more modern then the mysqli extension. for item #2, the simplest way of doing this is to use prepared queries, which provides protection for all data types. converting any query to a prepared query is straightforward - remove the php variables (keep these for later) and any single-quotes, {}, and quotes/concatenation dots that were used to get the variables into the sql query statement. put a ? place-holder into the sql query statement for each variable you removed. prepare the query. supply an array of the variables to the ->execute([...]) call. note: any wild-card search characters, typically used with a LIKE comparison, are part of the value, not part of the sql query statement. for item #3, as of php8, both the mysqli and PDO extensions use exceptions by default for all the database statements that can fail - connection, query, exec, prepare, and execute. this simplifies your code, since you can remove any existing error handling logic. the only database exceptions you should catch and handle in your code are for user recoverable errors, such as when inserting/updating user submitted data (which you are not doing in this case.) in all other cases, simply let php catch and handle any database exceptions, 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.)
  9. you would not UPDATE amounts in a table to track this data, since that doesn't provide an accounting trail should a programming mistake, duplicate entry, or nafarious activity alter a value. these are derived amounts that you would calculate when needed. you would have an invoice_accounting (or similar named) table, that gets a row inserted for every amount that affects an invoice amount. you would query when needed (a UNION between the invoice(s) table and the invoice accounting table) to determine the current total +/-/0 for any invoice.
  10. programming already is a tedious typing task. don't make it harder than it needs to be. buried within the unnecessary echoing of static html markup, is the problem. form fields must have a name='...' attribute for the value to be included in the submitted form data. here's a list of practices the will simplify and help secure the code - use 'require' for things your code must have for it to work to get a form to submit to the same page it is on, leave out the entire action attribute don't pass display messages or message flag values through the url, as this opens your site to phishing attacks any dynamic value you output in a html context needs htmlentities/htmlspecialchars applied to it to help prevent cross site scripting. you have some cases using this and some that are not the search form needs to be a get method form, it needs to be sticky and repopulate the field value with any existing data so that the user can just alter the value if a search didn't produce the result they were looking for the code for any page needs to 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 don't copy variables to other variables for nothing. just use the original variables you need to trim all user entered data, mainly so that you can detect if it was all white-space characters you need to validate all inputs before using them don't echo static css/html/javascript functions should return the result they produce, i.e. don't echo output inside a function, return it to the calling code don't use php functions, with css/html/javascript in them to build the html document use implicit binding and simply supply an array of input values to the PDOstatement ->execute([...]) call set the default fetch mode to assoc when you make the PDO connection so that you don't need to specify it in each fetch statement require/include are not functions. the () around the path/filename do nothing and should be removed
  11. you should use a data-driven design, with an array that maps the data field to the database column, then dynamically build the sql query statement and get the data values, by looping over the defining array. this will prevent typos, mismatched entries,... and allow you to change what the code does simply by changing the defining array.
  12. you also need to profile your code (calculate differences in microtime(true) values for the different operations on the page) to determine where it spends its time. i suspect that the time taken on the server isn't where the problem is, but in the execution of the javascript in the browser.
  13. 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 all the database specific code you have on this page should be in section #3 in this layout. this makes it easier to write, test, and debug your code and query(ies), and now that you need to modify the code/query(ies), puts it all in one place. if you are only getting a count of the number of matching rows, don't select all the columns (SELECT *) and all the rows. use a SELECT COUNT(*) ... query instead, then fetch the count value. the three queries getting a count of the number of matching rows with status = 0, 1, and 2 can be done in a single query. you can get the SUM(amount) and COUNT(*), where the rest of the query is the same, in a single query. lastly, the json_encode() should not be inside the loops. this is repeatedly encoding the array after each row is added, leaving only the last result. this probably where the most time is being taken. the json_encode() statements should be after the end of the relevant loop.
  14. there's a setting - https://www.php.net/manual/en/ini.core.php#ini.max-file-uploads
  15. there are xAMP pre-built systems you can download and install on windows, e.g. https://www.apachefriends.org/
  16. from a reply in your previous thread - also in your previous thread, two different forum members (ignoring the chatbot replies by the 3rd respondent in that thread) pointed out that you need to change all the short opening php tags to full <?php tags. i also use windows (10) for development, with PDO and php8.
  17. the key/index for the 'a+' entry is 0. this is a boolean false value, so the if() logic branch is skipped. you need to perform an exact match for a non-false value. e.g. !== false
  18. at about line 105 in Statement.php is a short opening tag.
  19. you are seeing the raw php code in the browser because of the short opening <? tag. always use full opening <?php tags. you should not make a new database connection in every function. your main code should make one database connection, then supply it as a call-time parameter to any function that needs it. if doing this requires too much restructuring of the existing code, the connectDB() function should define a static variable to hold the connection, then test for and only make a new connection if there is not already one. the default setting in php8+ for PDO errors is to use exceptions for all the database statements that can fail. you should only catch and handle database exceptions for user recoverable errors, such as when inserting/updating duplicate or out of range data. in all other cases, simply let php catch and handle any database exceptions, 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.)
  20. 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.
  21. form fields need a name="..." attribute, e.g. name="firstname", ... if you are just starting out, forget about using the overly complicated and inconsistent mysqli extension. instead, use the much simpler and more modern PDO extension, and use prepared queries. you should also put the form and form processing code on the same page, as this results in the simplest code. 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.
  22. 1st of all, all the post data you send in the request will be set (is_category, sales, material, salesoffice), so there's no point in testing if it is set, because it will be. if using a post request, just detect if the REQUEST_METHOD is 'POST' you should actually be using a get method request when determining what will be displayed on a page. while I'm pretty sure this has already been covered in a previous thread, you should be using a data-driven design (which is probably what the $column array is part of.) so what are you actually trying to accomplish? include a column/value in the WHERE clause if there is a non-empty value for that input? to do this, you don't need to write out code for every possible combination. regardless of using a data-driven design or conditional logic (once) for each input, you only need code that includes a column/value if there is a non empty value for that input. // using a data-driven design, define permitted WHERE columns and corresponding inputs $where_columns = ['sales_doc_type'=>'sales', 'material'=>'material', 'sales_office'=>'salesoffice']; // array to hold where terms $where_terms = []; // array to hold prepared query input parameters $params = []; // build the where terms foreach($where_columns as $col=>$input) { if($_POST[$input] ==! '') { $where_terms[] = "`$col`=?"; $params[] = "$_POST[$input]"; } } // build the WHERE clause $where = ''; if(!empty($where_terms)) { $where = 'WHERE ' . implode(' AND ',$where_terms); } // build the sql query $sql = "SELECT * FROM billing $where"; // examine the result echo $sql; echo '<pre>'; print_r($params); echo '</pre>';
  23. getting the current highest MAX() value and incrementing it in your code is not concurrent safe. if there are multiple instances of your script running at the same time (you must assume that this is possible), they will all get the same starting value, resulting in duplicate ids. the correct way of doing this is to have a table with an autoincrement primary index, insert a row of 'main' data, get the last insert id from that query and use it when inserting the data related to each 'main' row of data.
  24. once you switch to using a .csv file, you need to use a data-driven design, where you simply define a data structure (array) that controls what general purpose code does. see the following (untested, but should work) example - <?php /* data used - [0] => Sales Document Type [2] => Billing Date [11] => Material [25] => Gross Amount [45] => Sales Office [47] => Plant */ /* note: if you insure that the order in the following definition matches the order in the data file, you can use the array intersection method in the following code. otherwise, you must use the (commented out) loop method in the following code. */ // define mapping of data index to database column $db_col = [0=>'Sales_Document_Type', 2=>'Billing_Date', 11=>'Material', 25=>'Gross_Amount', 45=>'Sales_Office', 47=>'Plant']; // database table name $table = 'billing'; // number of initial lines to skip in the file $skip = 1; // for demonstration purposes, the file is hard-coded to be the converted csv of the example . xlsx file // in the actual code, this would be set to the temporary uploaded file $file = 'Aug Spares.XLSX - Sheet1.csv'; // open file if (($handle = fopen($file, "r")) !== FALSE) { // dynamically build the sql query $sql = "INSERT INTO `$table` (`".implode('`,`',array_values($db_col))."`) VALUES (".implode(',',array_fill(0,count($db_col),'?')).")"; // this example uses the much simpler and more modern PDO database extension $stmt = $pdo->prepare($sql); // start line counter at 1 $line = 1; // read lines from file while (($row = fgetcsv($handle, 1000, ",")) !== FALSE) { // process lines after initial skipped lines if($line > $skip) { // special processing // convert Billing_Date to standard format $row[2] = date('Y-m-d', strtotime($row[2])); // remove comma separator from Gross_Amount $row[25] = str_replace(',', '', $row[25]); // build array of value using array intersection method $params = array_values(array_intersect_key($row,$db_col)); /* // build array of values using a loop $params = []; foreach(array_keys($db_col) as $key) { $params[] = $row[$key]; } */ $stmt->execute($params); } $line++; } fclose($handle); } else { die('unable to open uploaded (temporary) file'); }
  25. the session variable is a 'required' input to your code. you must 'validate' it before using it, i.e. the current user must be logged in, in order to be able to see the team creation form and process the form data. if there is not a logged in user, you must take an appropriate action and not allow the current user to see the form or be able to run the form processing code. next, the only piece of user data you should store in a session variable upon successful login is the user_id. you should query on each page request to get any other user data, such as the username. this will allow this other user data to be edited and the change will take effect on the very next page request. likewise, you should not store the username in the players table. this is duplicating data that's defined/stored elsewhere. if you have the player's user_id, you would query when needed to get the player's username. if you were doing this for real, you would need to run the set of INSERT queries as part of a transaction, so that if either query failed with an error, they can both be rolled back. you also need to define the teams teamname and tag columns as unique indexes, to prevent duplicates, and have error handling that tests the result of the teams insert query for a duplicate index error (number.) the players userid and team_id columns must be defined as a composite unique index, to prevent duplicates (assuming that a player can only be on one team at a time), and have error handling that tests the result of the players insert query for a duplicate index error (number.)
×
×
  • 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.