Jump to content

mac_gyver

Staff Alumni
  • Posts

    5,537
  • Joined

  • Days Won

    192

Everything posted by mac_gyver

  1. see this post - also, don't select all the columns and all the rows to get a total count of rows/pages. use a COUNT(*) query and you don't need an ORDER BY term in this query.
  2. it means only write code that contributes something useful to what your application is trying to accomplish. for connection errors and errors from query(), prepare(), and most execute() calls (except for duplicate or out of range errors when inserting/updating user submitted data), there's nothing the visitor to your site can do to recover from the error, they are due to programming mistakes or a database server that's not running, ... therefore, there's no point in writing any code for these cases. just let php catch the exceptions in these cases and display (when developing code/query(ies)) or log (when on a live/public server) the actual error information, so that you, the programmer/developer, will know when these type of errors are occurring, so that you can find and fix what's causing them. the only types of database errors that the visitor to a site can do anything about are when inserting/updating duplicate or out of range visitor submitted data. this is the only case where having database error handling code in your application will do anything useful. you would catch the database exception, test the error number, setup a message telling the visitor exactly what was wrong with the data that they submitted, so that they can potentially submit a different value that will succeed.
  3. there's no good reason to have a try/catch block for the connection code. this is just typing for nothing. a connection error is a fatal problem for a database dependent web page. just let php catch any connection exception, where php will 'automatically' display/log the connection error for you. Keep It Simple (KISS.)
  4. the ~3500 lines of phpmailer code should not be in-line in your file. they should be in external file(s) that get required by the main file. i see that you have hard-coded the to: and subject: values in the code. these and the still present 'sendmethod' should have never come from the form. i recommend that you delete any remaining logic using the 'sendmethod' value. this code is using ajax to submit the form data, therefore nothing the server-side post method processing code does to try to redirect will have any effect on the form page. it would take javascript code in the ajax completion code ( if ( request.readyState==4 ) { ) to test a value returned to it by the server-side code to either display a message or take an action, such as redirecting to a different page.
  5. VSC reporting that the function is not defined is because VSC is not smart enough to know that the function can be defined in a separate file or if the code you posted at the top of this thread is an accurate arrangement of code in a single file (doubtful now), that you can define a function anywhere in a php project with respect to where it is called, provided it's not conditionally defined or conditionally required/included (the first two cases I posted.) You have been side-tracked by VSC's reporting of a problem that doesn't actually exist. You are going to have to actually learn the fundamentals of php programming so that you are smarter then the Microsoft tool you are trying to use.
  6. relying on a Microsoft product as a programming aid is foolish. if you are not posting actual errors that you got from PHP on your localhost web server when you tried to run your code, you are wasting yours and our time. if you are not posting, copy/pasting, your actual code, you are wasting our time as well.
  7. the posted code contains a php syntax error (a closing ?> tag inside the function definition) and doesn't run at all, so that's not the actual code producing that error. a few possibilities why the function definition is not present in the current program scope - the function definition is inside of a conditional statement, and so isn't defined until the code where that statements is at has been executed and the conditional statement is true. the function definition is inside of another function definition, and so isn't defined until the parent function has been called. the function definition is being required (you should use require for things your program just have) using a url, not a file system path, and is not in the same instance of your program as the function call. after you correct the php syntax error, the posted code produces an undefined constant error because the function call is before the point where the constants are defined. it would take seeing the actual code producing the error to help with what is wrong with it.
  8. if you use the email address, that was just created for you at your web hosting, as the To: email address, you can probably get the mail() function to work.
  9. gmail has recently stopped accepting emails that are being sent by unknown, unauthenticated email clients/systems, such as a sending mail server at some random web hosting. you must generate an OAuth token and use it to authenticate when sending to gmail. see the following post and thread it is in - prior to this, you were required to use smtp authentication against your gmail mailbox, which the php mail() function does not support, so you need to use either the phpmailer or swiftmailer class in any case.
  10. most database errors are fatal problems, due to programming mistakes, or due to data issues like have been listed in this thread. since there's no user interaction with this code, there's no case where a database statement error is recoverable by the non-existent user. therefore, all database statement errors should simply get logged. the simplest way of doing this, which requires no code in the application (the current catch logic, if it is being executed at all, is only logging the error message, it does not include the filename and line number where the error occurred, and it is allowing execution to continue when a fatal problem has occurred) is to use exceptions for database statement errors and simply let php catch 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 PDO connection already always uses exceptions for errors, but if there's tri/catch code present that isn't properly dealing with a connection error, it's not helping, and should be removed anyways. setting the PDO error mode to use exceptions, applies to all the rest of the statements - query, prepare, and execute. after insuring that this is being set, for what this application is for, any try/catch code should be removed so that php will catch the database exceptions.
  11. as a separate post. this code is typical misuse of OOP. someone took a few lines of main code, building and executing an insert query, threw a class definition around it, then to make it 'work' had to add $this-> in front of everything, add a bunch more code to build the input properties, code to instantiate the class, code to call the various methods, code (if any) to test the returned values, and code (if any) to use the output properties. if this method gets called and there isn't a database connection (what the first few lines of code are testing), it means that the connection code doesn't have error handling that would have stopped the whole database dependent application from being executed upon a connection error, and for the rare cases where a connection was successfully made, but lost during execution of the code, the fatal php error that would have occurred when the non-existent connection was used should be getting logged to let you know what type of problems are occurring. edit: since the code is just returning in this case, and it's doubtful that the returned value is causing any sort of logging/reporting to occur, you will never know if this is the cause of the missing inserted data. this brings up an additional point for debugging the problem. php's error_reporting should be set to E_ALL and log_errors should be set to ON, preferably in the php.ini on the system, so that all php errors will get reported and logged. if the php/web server error log is empty, either this is not the case or the log file settings are not setup.
  12. if the PDO error mode IS set to use exceptions, the $this->_debugOn code won't have any effect, since it won't ever get executed upon an error. if the PDO error mode is not set to use exceptions, the $this->_debugOn code will be executed, but it is then up to the application code to actually test and use those class properties. since this code apparently doesn't have a user interface, the $this->_debugOn code was probably only ever there for direct requests during developmental testing. for the the try/catch code to 'work' the PDO error mode must be set to use exceptions. there would be something in the database connection code using PDO::ATTR_ERRMODE and PDO::ERRMODE_EXCEPTION if this setting is on. without investigating (logging) what the actual sql syntax being built is and what is being supplied to the ->execute(...) call, there's no guarantee that this is an actual prepared query, and if an emulated prepared query is being used, sql special characters in a value can still break the sql query syntax if the character set that php is using is not the same as the character set of the database tables. posting the database connection code, less any connection credentials, would show the error mode setting, emulated prepared query setting, and any character set setting.
  13. when data insertion fails occasionally, it's usually because of sql special characters in a value breaking the sql query syntax, data containing duplicate values that violate a unique index or other constraint, or data that is out of range for a column definition. these conditions would produce query errors, so, the question becomes does the php code have error handling for all the database statements that can fail - connection, query, prepare, and execute that would be logging the errors to the php error log or is the mysql general query log enabled (it's not by default)?
  14. here's a big problem with the existing table per category. the ids are repeated, so, having an id doesn't uniquely tell you what the item is, nor does it let you find (sub)items related to the item. when someone selects an item, you cannot just store the item id and the quantity. you must also store the category_id, requiring more data storage and more code for every operation. are you actually reading and getting the information in the replies? there's a post above stating how simple you can build the category and item tables from the table data you have shown us. the code to do so would look like (untested) - <?php // get or build a list of table information $tables = []; // table - is the existing table name // name - is the item name, which unfortunately repeats part of the table name, making everything harder than necessary // category - is the desired category name $tables[] = ['table'=>'rifles','name'=>'rifleName','category'=>'rifle']; $tables[] = ['table'=>'shotguns','name'=>'shotgunName','category'=>'shotgun']; // add entries for the rest of the tables here... // query to populate category table $sql = "INSERT category (name) VALUE (?)"; $cat_stmt = $pdo->prepare($sql); foreach($tables as $table) { // insert the category data $cat_stmt->execute($table['category']); $cat_id = $pdo->lastInsertId(); // query to populate item table $sql = "INSERT item (category_id, name, em, gm) SELECT $cat_id, `{$table['name']}`, em, gm FROM `{$table['table']}`"; $stmt = $pdo->query($sql); }
  15. if you look again, the seconds are not used. the php date format string would be - Y-m-d\TH:i
  16. one of the points was properly organizing the data in the database - which brings up the programming motto - a good database design supports good code design. you can build the category and item tables from your existing tables by using a dynamically built INSERT ... SELECT query and some code to get and loop over all the table names.
  17. php installation was probably updated and turned off the output_buffering php.ini setting, resulting in previously working bad code to stop working.
  18. the code i posted is a data-driven design. it takes the input data that is supplied to it and dynamically produces as many select/option menus as there are categories in the data. the javascript is also general-purpose and will work as is regardless of how many different select/option menus there are. there's no need to touch any of the actual code, unless there's a mistake that needs to be fixed or an actual change is desired. if you comment out the database specific code, and un-comment the fake data code, you can try this by itself to see how it works.
  19. see the following example, using the above points (tested with fake data) - <?php // initialization $servername = "localhost"; $dbport = '3306'; $dbname = 'ehr_tracker'; $dbuser = 'root'; $dbpass = ''; // when you make the connection, also set the default fetch mode to assoc, so that you don't need to specify it in each fetch statement // there's no good reason for you to catch a connection error, just let php catch it. // also, don't output the raw database errors, as these only help hackers. // likewise, a connection error is a fatal problem and code should stop executing in order to prevent follow-on errors. $pdo = new PDO("mysql:host=$servername;dbname=$dbname;charset=utf8;'", $dbuser, $dbpass, array(PDO::ATTR_EMULATE_PREPARES => false,PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); // get method business logic - get/produce data needed to display the page // the following assumes you want all category data, // if not add a WHERE clause to get just the categories you want $sql = "SELECT c.name category_name, i.id, i.name, i.em, i.gm FROM items i JOIN category c ON i.category_id = c.id ORDER BY c.name, i.name"; $stmt = $pdo->query($sql); // fetch the data, indexing/pivoting it by the first column selected - category_name $item_data = $stmt->fetchAll(PDO::FETCH_GROUP); /* // fake some data $data = []; $data[] = ['id'=>'1', 'name'=>'r1', 'em'=>'10', 'gm'=>'12', 'category_name'=>'rifle']; $data[] = ['id'=>'2', 'name'=>'b1', 'em'=>'20', 'gm'=>'22', 'category_name'=>'bow']; $data[] = ['id'=>'3', 'name'=>'b2', 'em'=>'25', 'gm'=>'27', 'category_name'=>'bow']; $data[] = ['id'=>'4', 'name'=>'s1', 'em'=>'30', 'gm'=>'32', 'category_name'=>'shotgun']; $data[] = ['id'=>'5', 'name'=>'s2', 'em'=>'33', 'gm'=>'34', 'category_name'=>'shotgun']; $data[] = ['id'=>'6', 'name'=>'s3', 'em'=>'37', 'gm'=>'38', 'category_name'=>'shotgun']; // index/pivot the fake data like the FETCH_GROUP would produce $item_data = []; foreach($data as $row) { $item_data[ $row['category_name'] ][] = $row; } //echo '<pre>'; print_r($item_data); echo '</pre>'; */ // html document starts here... ?> <html> <head> <style> body { background: black; color: white; } input { background: black; color: white; border: 1px solid orange; text-align: center; } select, selection { background: black; color: white; border: 1px solid orange; } table { border: 1px solid gray; border-collapse: collapse; } </style> </head> <body> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script> $(document).ready(function() { $(".populate_em_gm").change( function() { let em = $(this).find("option:selected").data("em") let gm = $(this).find("option:selected").data("gm") $(this).closest('tr').find('.em').val(em) $(this).closest('tr').find('.gm').val(gm) }) }) </script> <table border="1"> <tr><th>Items</th><th>em</th><th>gm</th><th>+</th><tr> <?php foreach($item_data as $category_name=>$arr) { $cn = ucfirst($category_name); echo "<tr><td colspan='2'>{$cn}s</td><td></td><td><button type='button'>+</button></td></tr>"; echo "<tr><td>"; echo "<select class='populate_em_gm' name='$category_name'>"; echo "<option value=''>Choose a $cn</option>"; foreach($arr as $row) { echo "<option value='{$row['id']}' data-em='{$row['em']}' data-gm='{$row['gm']}'>{$row['name']}</option>"; } ?> </select></td> <td><input type="text" class="em" value="0" disabled size="5"/></td> <td><input type="text" class="gm" value="0" disabled size="5"/></td> <td>+</td> </tr> <?php } ?> </table> </body> </html>
  20. writing out, copy/pasting/overtyping, code for every possible value/category is not programming, that's you being a human-keyboard-macro. you are not using the computer as a tool to accomplish a task, the computer is using you. your database design should have a category table, with id and name columns. this would establish category_ids. you should have an item (or similarly named) table with id, category_id, and name columns. you would then just use one query to get the data that you want and loop over it to produce the output. to add new categories or add items under a category, you would just insert the data into the appropriate table(s), and the code would 'automatically' use the new values without you needing to touch the code. you would take a similar Don't Repeat Yourself (DRY) approach in the html and javascript, where you would dynamically build the output sections by looping over the data, putting each select/option menu and em/gm fields in a 'container', that one instance of general-purpose javascript would operate on to populate the correct em/gm fields when there's a change in the corresponding select/option menu.
  21. that's not the correct format, resulting in different browser/operating system/local system defaulting to what they think they should do. did you read the information at the developer.mozilla.org link that was given?
  22. the format for the value of a datetime-local field is - YYYY-MM-DDThh:mm ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local
  23. why are you using two different names for the same meaning data? besides the existence or absence of the id, what's different about the edit vs create form? can you not just always have a hidden id field that has a value if editing an existing entry or is empty when creating a new entry? your post method form processing logic should be - detect if a post method form was submitted perform common tasks, such as trimming all the input data at once, validating the common inputs between both processes test if the id is empty or not if the id is empty, run the unique code for creating a new entry else, run the unique code for updating an exiting entry
  24. the following is the SELECT query prototype definition, with the elements you will need in bold - SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [PROCEDURE procedure_name(argument_list)] [INTO OUTFILE 'file_name' [CHARACTER SET charset_name] export_options | INTO DUMPFILE 'file_name' | INTO var_name [, var_name]] [FOR UPDATE | LOCK IN SHARE MODE]] the select_expr would include a COUNT() term to get the number of matching rows per group, along with any other columns you want in the result. the FROM table_references would include a JOIN between the two (or is it three as the title says) tables. the WHERE where_condition would match the column and value for billable items. the GROUP BY col_name would group by the customer id/name column. the ORDER BY col_name would sort the results the way you want, such as by the customer name. give this a try.
  25. here's a correction to the above, move the closed != 1 codition to the sub-query - SELECT q.id as quoteId, q.job_id as jobId, j.name as jobName, j.client_id as clientId, c.name as clientName, q.currency, q.version FROM quote q JOIN job j ON j.id = q.job_id JOIN client c ON c.id = j.client_id WHERE q.id IN(SELECT MAX(id) FROM quote WHERE closed != 1 GROUP BY job_id)
×
×
  • 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.