-
Posts
5,450 -
Joined
-
Days Won
175
Everything posted by mac_gyver
-
my comments apply to all the code. since barand started with your code and added things to demonstrate how to make it work - input conditioning, default input values, a prepared query, a working get method, sticky, search form, and left the remainder as is, yes, these comments apply to the result of adding these programming practices to the starting code.
-
some points about the code/query - when you have a list of ORed terms in a query, use a single IN() comparison instead. don't put quotes around numbers. be consistent. one number in the query isn't quoted. use 'require' for things your php code must have for it to work. for a <label> tag to work, you must either put the correspond form field somewhere between the opening and closing label tags, with the label text, or you must put a for='...' attribute inside the opening label tag and a corresponding id='...' attribute inside the form field. you should validate your resulting web pages at validator.w3.org any dynamic value you output in a html context should have htmlentities() applied to it to help prevent cross site scripting.
-
your column names imply that sales.sales_repid contains matching reps.rep_id values. if the query didn't produce any result, that indicates there isn't matching data, either in the join condition or in the where clause. you would need to post an example of the data that the query should match for anyone here to have a chance at helping with the problem.
-
the fun part in programming is learning new things and in succeeding in getting the computer to do what you want. copy/pasting things someone else has written isn't programming. i had never previously dynamically built a hyperlink using javascript. i began by researching (i.e. keep searching) until i found how to set the href attribute and how to set the innerText using javascript. since the method i used above uses jquery and is finding the class names within each row, i starting by giving an empty hyperlink markup a class name of 'file' - <a class='file' target="_blank"></a> then the code to dynamically build the hyperlink, using the javascript Directory and Document variables, became - $('#Aid_'+Aid).find('.file').attr("href", '/'+Directory+'/'+Document); $('#Aid_'+Aid).find('.file').text(Document); you would need to research what these would need to be when not using jquery (my previous post above names the two attributes) and using the composite ids being used in the code you copied.
-
since your version didn't even put values into the json data, neither of the respondents attempted to fix that part of the code. i recommend that you supply the directory and document values separately in the json data. in the ajax success code, you would create javascript variables for both of those values. since this isn't a form field, it doesn't have a .value attribute (what your code was trying to do.) to set the href value, you would set the .href attribute with a relative url made up from the directory and document values. to set the display text, you would set the .innerText attribute with the document value.
-
your database design is not normalized. this results in repeating the same data values over and over. you should have a column for, and store the Ass_ID value in the mykra table, instead of repeating the 'Point_Description' and 'Point_Marks' values in every row in that table. doing this will also simplify and help secure the form code, since you will no longer be passing the description[] and rating[] fields through the form, and it will simplify the ajax related code. some points about the code - you need to stop copying variables to other variables for nothing. this is just a waste of your time typing. just use the original variables that data is in. you need to go through the code and eliminate all the unused code and unused variables. an empty action='' attribute is not valid html5. to cause a form to submit to the same page it is on, leave out the entire action attribute. you cannot set the value attribute of a type='file' field, so you might as well remove that from the ajax code (you aren't setting a 'file' value in the json data, so that code wasn't doing anything anyways.) you would want to build/output the href link using directory/document data. if there is a validation/user error in the post method form processing code, the form fields need to be 'sticky' and repopulate their values with any existing form data, so that the user doesn't need to keep reentering/editing values over and over. you havn't posted it yet, but the insert/update query (there's a single query to do this) could result in duplicate data. you need to handle this in the code and setup an error message for the user letting them know what was wrong with the data that they submitted, so that they can modify the offending value and resubmit the data again. you need to validate the resulting web pages at validator.w3.org as to getting this to work, the Ass_ID value is the 'key' to finding the correct <tr> row of form inputs to operate on. it is also the 'key' to inserting/updating the correct rows of data in the database table when the form is submitted. in the html table/form code, you need a hidden array field with the Ass_ID values in it. this will let you associate the submitted Ass_ID values with the corresponding data from the other form array fields. you also need a way of referencing the <tr> for each row. to do this add an id='...' attribute, such as - <tr id='<?='Aid_'.$row['Ass_ID']?>'> in the Mykra_view.php code, you need to build the json data with the Ass_ID value, such as - $return_arr[] = array( 'Aid' => $row['Ass_ID'], // add the Ass_ID to the json data "target" => $row['Marks_Target'], "actual" => $row['Marks_Actual'], "date" => $row['DOS'], "remarks" => $row['Marks_Description'] ); then in the ajax success code, you would get the Aid value and use it to select/find the correct form field value to set with the data - <script> function viewData() { var month = document.getElementById("Month").value; var employeeid = document.getElementById("employeeno").value; $.ajax({ type: 'get', dataType: 'JSON', url: 'Mykra_view.php', data: 'Month=' + month + '&employeeno=' + employeeid, success: function (response) { var len = response.length; for (var i = 0; i < len; i++) { var Aid = response[i].Aid; var target = response[i].target; var actual = response[i].actual; var date = response[i].date; var remarks = response[i].remarks; $('#Aid_'+Aid).find('.target').val(target); $('#Aid_'+Aid).find('.actual').val(actual); $('#Aid_'+Aid).find('.date').val(date); $('#Aid_'+Aid).find('.remarks').val(remarks); } } }); } </script> to make the above work, like in your previous thread, you would change the id='...' attributes to class='...' attributes (you would actually add the class names to the existing class='...' attributes.)
-
the only redirect you should have in your post method form processing code should be upon successfully logging in and it should be to the exact same URL of the current page to cause a get request for that page. if you don't do this, anyone can use the browser's developer tools network tab to see what the submitted username and password are. if you want the user to be able to go to a different page, provide navigation links, or ever better, integrate the login system with any page that needs it. by putting the form and form processing on different pages and doing this - header("location:login.php?msg=error"), you are opening your site to a phishing attack, where someone can trick your users to enter their username/password on the phishing site, then redirect to your site and make it look like they mistyped their information.
-
the column in question in the bandstage table is apparently mybandid
-
so, how about the var_dump output? if you actually use all the points made, including switching to the much simpler and more modern PDO database extension, you will get code that looks like this (untested) - <?php // initialization session_start(); $errors = []; // array to hold user/validation errors // post method form processing if($_SERVER['REQUEST_METHOD'] === 'POST') { // validate input data if(!isset($_SESSION['id'])) { $errors['logged_in'] = 'You must be logged in to delete your bandstage data.'; } // if no errors, use the input data if(empty($errors)) { require 'pdo_connection.php'; $sql = "DELETE FROM bandstage WHERE id = ?"; $stmt = $pdo->prepare($sql); $stmt->execute([ $_SESSION['id'] ]); } // if no errors, success if(empty($errors)) { // note: if you want to display a one-time success message, store it in a session variable, then test, display, and clear that variable in the html document $_SESSION['success_message'] = 'You have successfully deleted your bandstage data.'; // redirect to the exact same url of the current page to cause a get request for the page - PRG Post, Redirect, Get. die(header("Refresh:0")); } } // get method business logic - get/produce data needed to display the page // html document // note: this in incomplete and only shows the parts corresponding to this example code ?> <?php // display and clear any success message if(isset($_SESSION['success_message'])) { echo $_SESSION['success_message']; unset($_SESSION['success_message']); } ?> <?php // display any errors if(!empty($errors)) { echo implode('<br>',$errors); } ?>
-
using var_dump() on the session variable (see my reply above) will help identify if it contains any non-printing/white-space characters. if by that you mean the header() statement. no, he told you to put that line of code - at the header() statement, it is too late to put in that line of code. does that mean you have multiple databases or does that mean you actually have only one database, but it has multiple tables in it? if you do have multiple databases, are you selecting the correct one and is that the same one you are looking at to see if the records are being deleted?
-
what result or output are you getting on this page? what does adding the following, after the session_start(), show - var_dump($_SESSION['id']); a bunch of points about the posted code - the php error related settings should be in the php.ini on your system. if you put the database connection code in a separate .php file, you can just require it when needed. this will save you from having to redact the connection credentials when posting the code. the line that barand posted, which enables exceptions for errors, should always be part of your code. this is also the default setting in php8+ don't output raw database connection onto a web page or tell the visitor that a database error occurred. this only helps hackers. when using exceptions for database statement errors, the error handling logic you have now won't ever be executed upon and error and should be removed, simplifying the code. you should set the character set when you make the database connection to match your database tables, so that no character conversion occurs over the connection. you should be using a post method form when performing an action on the server, such as deleting data. if this a get method button/link, when a search engine indexes your site, you could end up with a bunch of your data getting deleted. $_SESSION['id'] is an 'input' to your code. you must validate it before using it. technically, you should trim() it before validating it if it could have accidentally gotten modified when putting the value into the session variables. don't copy variables to other variables for nothing. just use the original variables. you should also be using a prepared query when supplying external, unknown, dynamic value to a query when it gets executed. php automatically destroys all resources on a page when your script ends. there's no need to close database connections in your code. upon successful completion of post method form processing code, you should perform a redirect to the exact same url of the page to cause a get request for that page. this will prevent the browser from trying to resubmit the form data should the user reload or navigate away from and back to that page.
-
exactly what settings and what values did you set them to? you should set error_reporting = E_ALL (this value is case-sensitive) and set display_errors = On (this value is not case-sensitive) and these lines should not be commented out. did you stop and start your web server to insure that any changes to the php.ini took affect? what does the phpinfo() output show for these settings after you have attempted to set them and restarted the web server?
-
i don't think anyone understands, based on the description, what the overall work flow is. could you describe or show what the user should see at each step. you state the html table should be empty while the page is loading, but you show php code looping over the result of some not-shown query producing that html table output. if the purpose of this php code is to produce a 'template', which the ajax success code is supposed to populate with values, you need to tell us? you would also not use a loop. you would only output one instance of the markup. the only thing i can tell you based on the posted attempt is what has been written in your threads before, you cannot repeat ids in the markup. all the code like - id="Ass_Description" will not work when there is more than one instance on a page. you need to use the technique from the last thread, where class names are used, then you use the .find() method to reference each element.
-
https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html
-
the boolean value returned by the exaction of a SELECT query only indicates that the query executed without error (a true value) or failed due to a query error (a false value.) it doesn't indicate that the query match any data. a query that doesn't match any data is a successful query, but returns an empty result set. there's a single query that does what you want. an INSERT ... ON DUPLICATE KEY UPDATE ... query. you would define the uid column as a unique index if it is not already defined that way. there's no need to try to select data in order to decide if you should insert new data or update existing data and in fact, there's a race condition in the existing code where multiple concurrent instances of your script can all find that data doesn't exist and will all attempt to insert the same data, resulting in duplicates or in errors. also, use a prepared query when supplying external, unknown, dynamic values to a query when it gets executed. there's two reasons for doing this - 1) addslashes() doesn't protect against every possible character that can break the sql query syntax, since it doesn't take into account the characters set of your database tables, which is why php remove its ridiculous magic_quotes a long time ago, and 2) it will provide a performance increase when executing the same query more than once within one instance of your script.
-
PAGINATION 1 - mysqli_stmtm_store_result() Query
mac_gyver replied to TheStudent2023's topic in PHP Coding Help
this code can be greatly simplified, because writing out code for every input or combination of values is not effective programming. switching to the much simpler and more modern PDO database extension will eliminate about half of the database statements. this alone will answer your database questions since the PDO extension was designed to be simple and usable. here's a specific list of practices, most of which will simplify and clean up the code - put the php error settings in the php.ini on your system, so that you can set/change them at a single point. you cannot set display_startup_errors in your code because php has already started when your code is being executed. 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. most of the php code needed for searching/pagination goes in the get method business logic section. post method forms are used when performing an action on the server, such as inserting, updating, deleting data, sending an email, writing/updating a field. get method forms/links are used when determining what will be displayed on a page, e.g. searching, pagination. the second entry in the $tbls array contains a $. did you actually use this array to validate the $tbl input? don't use the root database user in applications. create a specific database user, with a password, with only the necessary permissions for use in an application. don't output raw database errors onto a wab page. this only helps hackers. instead, use exceptions for database statement errors (this is the default for both the mysqli and PDO extension in php8+) and in most cases simply let php catch and handle any database statement error, 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. in this case, your code would catch the exception, test if the error number is for something your code is designed to handle, and setup a unique and helpful error message for the user. for all other error numbers, just re-throw the exception and let php handle it. this will let you remove all the existing database error handling logic, simplifying the code. btw - mysqli_stmt_execut() can fail with an error but you don't have error handling logic for it, but since you will be removing all the existing error handling logic when using exceptions for database statement errors, you won't have to remove this non-existent code. if you are going to continue to use the mysqli extension, don't use mysqli_stmt_init() followed by mysqli_stmt_prepare(), just use mysqli_prepare(). if you are going to continue to use the mysqli extension, use the OOP notation. it is both simpler and because the php error response is different between the procedural and OOP notation, things that are fatal problems will produce fatal php errors when using OOP, but only produce warnings when using procedural notation. in most cases, you don't need to free prepared statements, result sets, or close database connections since php will destroy all resources created on a page when your script ends. you should keep the input 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's basically copying each input to another variable. you should trim all input data before validating it. after you do the above item, you can accomplish this with one single line of php code. related to the above item, don't copy fetched data to other variables for nothing. just use the original variables that the data is in. you should store user/validation errors in an array, using the field/input name as the main array index. after the end of all the validation logic, if there are no errors (the array holding the errors will be empty), use the submitted data. if there are errors, the code will continue on to display the html document, test and display any errors, re-display any form, populating the form field values with any existing data so that the user doesn't need to keep reentering/selecting data over and over. any dynamic value you output in a html context needs to have htmlentities() applied to it to help prevent cross site scripting. at the point of dynamically building the sql query statement, the table and columns names can technically be anything and should be enclosed by back-ticks so as to not produce sql errors. are you sure you actually tested this? the definition for $links_table_columns doesn't exist in the code and even if it did, it is apparently permitted column names, so the error message would be for an invalid column, not an invalid table. pagination involves two similar queries. the first query is to get the total number of matching rows. the second query is to get the logical page of data. the common part of both of these queries should be built once, in a php variable, with a corresponding array of input parameters. the common part of the query is from the FROM term ... through to any HAVING term. the query to get the total number of matching rows should use SELECT COUNT(*) followed by the common part of the query, i.e. it should NOT select all the data just to get a count of the number of rows of data. the data retrieval query would instead SELECT the columns you want, followed by the common part of the sql query, followed by an ORDER BY term, and then the LIMIT term. you should supply the two LIMIT values via prepared query place holders and add (append/merge) the two values to the array of input values. since you will be using a SELECT COUNT(*) ... query to get the total number of matching rows, you won't need to deal with mysqli's mysqli_stmt_store_result() and mysqli_stmt_num_rows() don't use a series of name_x variables. use an array. arrays are for sets of data where you will operate on each member in the set in the same/similar way. you can then use php's array functions to operate on the arrays of data. the pagination link markup should be built in a php variable so that you can output the result wherever and however many times you want. use relative urls in the pagination links. this will eliminate PHP_SELF. to build the query string part of the pagination links, get an existing copy of any $_GET parameters (this will automatically include any table, input, col, bool, and limit values so that you don't need to write out code for each one) set/modify the page (pg) element, then use http_build_query() to build the query string. this will take care of urlencodeing the values. -
what symptom or error are you getting that leads you to believe that? btw - the only redirect you should have in your post method form processing code should be to the exact same url of the form processing code to cause a get request for that page. this will prevent the browser from trying to resubmit the form data should the user reload the page or navigate away from and back to that page, which will let someone use the developer console network tab to see what the username and password is. if you want the user to be able to go to some other page, provide navigation links.
-
first of all, don't bother with the mysqli extension. it is overly complicated and inconsistent, especially when dealing with prepared queries, which you need to use to prevent any sql special characters in a value from being able to break the sql query syntax, which is how sql injection is accomplished. instead, use the much simpler and more modern PDO extension. here's a list a do's and don'ts for the posted code - you need to use a prepared query when supplying any external, unknown, dynamic values to a query when it gets executed. this will require that you change any place there's an $sql input parameter to also include an array of input values, such as what would be present in a WHERE ... clause. you would also supply the offset and rows_per_page in the LIMIT term via prepared query place-holders and append the values to the array of input values. don't SELECT all the rows of data to get the total number of rows. instead, use a SELECT COUNT(*) ... query, then fetch the COUNT(*) value. the common part of the sql query, from the FROM ... term though to any HAVING ... term needs to be used for both the SELECT COUNT(*) ... and the data retrieval query. this is the value you should build in the $sql input parameter. just about every SELECT query that returns more than one row should have an ORDER BY ... term so that the rows of data are in a desired order. don't use PHP_SELF and all the related code/values. you can use relative urls in the links. when you build the pagination links, start with a copy of any existing $_GET parameters, set/modify the page parameter, then use http_build_query to build the query string part of the links. this will eliminate the need for the $append value. use exceptions for database statement errors (this is the default error mode for both the PDO and mysqli extensions in php8+) and in most cases simply let php catch and handle any database 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.) this will eliminate the need for the existing error handling and debugging logic. don't use the @ error suppressor, ever. there's no need. when learning, developing, and debugging code/query(ies), you should display all php errors. when running code on a live/public server, you should log all php errors. there's no need for the pagination code to test for a valid database connection. if the database connection fails, the page shouldn't ever get to the point of trying to use the connection for anything. 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 code to get the logical page of data and build the pagination links should be located in item #3 in this layout. OOP is NOT about wrapping a class definition around your main code and adding $this-> in front of everything to make it work. for example, the offset value is only used in one place. there's no need for it to be a class property. just use a regular/local variable for the value.
-
a <button> by itself doesn't do anything. a button with type='submit' must be part of a form. a button without type='submit' must have an event or javascript associated with it to do anything. you will need to put a complete post method form, with a button with type='submit', within the html table cell, for this to work.
-
conditional statements exist in programming languages so that you can write code that makes decisions when it runs, such as only outputting markup when there's data to display. the existing code has a conditional test in it to only output the markup inside the tbody if there is data to display. wouldn't the answer to your question be to move the start of that conditional test so that it only outputs the table/thead markup when there is data to display?
-
if you read the information that I posted, you will know why this doesn't work. you CANNOT repeat ids in the markup. you must use some other way of referencing the elements. i showed code to do this by finding the .closest parent container, then .finding an element with a class name within the parent container. the reason no one is posting fixed code is because you would not learn anything by just repeating what you see. programming is a writing and reading activity. you must actually understand the meaning of the words and syntax you are using. copy/pasting something that someone else writes doesn't do this.
-
your browser's developer tools console tab may contain errors that would help you find the problem. the OP only half did the first item i listed (added a class, rather than changing the id to a class), leaving duplicate ids in the dynamically added fields. the second item i listed was done. all the rest of the information i listed was ignored.
-
there are two reason this is not working - 1) ids must be unique. you cannot use id="Brand" more than once on a page, and 2) the dynamically added elements don't exist when you are attaching the on change event handler (even if you change the selector to be a class name.) you must attach the on change event handler to an element that exists at the time (document is the easiest, though not the most efficient), that will contain the elements you want the event handler to fire for. assuming you change id='Brand' to class='Brand', the following will attach the on change event handler to all instances of the <select class="Brand" ... within the html document - $(document).on('change', '.Brand', function(){ since ids must be unique, all the rest of the code manipulating the DOM must be changed so that they don't rely on ids. the way to do this is give the <tr a class name that you can search for, such as 'parent-container', you can then find the current parent container using - var parent = $(this).closest('.parent-container'); you can then find and reference the elements within the parent container, by a class name, such as - parent.find('.Category').html(html);
-
your web hosting probably has a Frequently Ask Question section that lists any requirements and a code example to send emails. you would need to post any code you have tried to get any help with what could be wrong with it. code examples you find on the web as usually lacking in security, lacking a good user experience, are filled with unnecessary typing, are missing error handling and validation logic that would get them to tell you (display/log) why they aren't working, and most, incorrectly, are using the email address that was entered by the visitor as the From: email address (these emails are NOT being sent from the email address that was entered, they are being sent from the mail server at your web hosting and the Form: email address must use a domain name that is either at your web hosting or is tracible back to the ip address of the sending mail server through dns records.)