Jump to content

mac_gyver

Staff Alumni
  • Posts

    5,348
  • Joined

  • Days Won

    173

Everything posted by mac_gyver

  1. when you used either scandir() or opendir()/readdir()/closedir(), did you you display everything or did your code attempt to conditionally display only files that started with '1'? could the file names start with a non-printing/white-space character so that they don't actually begin with a '1' character, either when they were created or through some copy or rename operation?
  2. the correct place to assign a value to the session variable is in the post method form processing code, at the point where you have confirmed that the username and password have been matched (it is currently not at this point in the code and needs to be corrected.) it should not be assigned a value in any other place. therefore, remove the assignment statement you currently/still have in sayfam.php. the debugging line of code, with print_r($_SESSION, true), should still be in sayfam.php, until you get this to work, since is shows if the session variable is set and what value it contains.
  3. the date format string to get the first day of the current month is - 'Y-m-01' you would not write out conditional logic (switch/case, if) for every possible value. if you did have a need to match a set of input values to output values, you would use an array, where the array index is the input value and the stored array value is the output value. you would display the redeem button based on a non-redeemed status value in the row of data. then update that status value to a redeemed value when the offer is redeemed.
  4. on each page request, you would query to find the date (holding the first day of the month) of the last row holding this free-play data for the currently logged in user. if it is older than the start of the current month, you would insert enough rows to get up to the current month. you should store related data using the user id (autoincrement primary index in the user table), not the username, so that the username can be edited without needing to go through and update all the related data.
  5. can you describe, in your native language, what $_SESSION['nik'] = $_POST['nik']; does and why it is in sayfam.php? in English, this line of code is assigning a post method from variable $_POST['nik'] to the session variable $_SESSION['nik'] and it doesn't belong in sayfam.php at all. that post variable only exists on the page that the form submits to, denetim.php. it doesn't exist when sayfam.php is requested, producing the undefined index error you are getting and clearing that session variable. what does the print_r() output show after you have removed that line of code from sayfam.php? note: as i already posted, you must completely close all instances of your browser and start over to cause the session variable to be set to the expected value. post the current code for sayfam.php? are you using google's online/browser translator to translate our replies into your native language? my first reply in this thread contains a lot of helpful information that would allow you to create an application that - is secure, provides a good User eXpeinace (UX), is simple and doesn't contain a lot of unnecessary typing, and through having error handling and validation logic, will either work or it will tell you why it doesn't work.
  6. the print_r() output is showing that the "nik" session variable is set, but it is empty. the warning on line 5 in sayfam.php is therefore coming from a reference to an undefined array key "nik" in some other variable. probably $_POST["nik"]. the OP's first post in this thread contained the code for sayfam.php. on line 4 in that code is an incorrect line of code setting - $_SESSION['nik'] = $_POST['nik']; the later post in this thread, with the three files of the code, where the last one is for sayfam.php, does not contain the line setting - $_SESSION['nik'] = $_POST['nik']; yet, there is now an error indicating that line of code is probably in (never removed from) sayfam.php, so, two problems. 1) the OP is not posting the actual code that is being executed, and 2) that line of code needs to be removed from sayfam.php, since it is setting the session variable to a null/empty value.
  7. the reason @dodgeitorelse3 asked you to identify, by filename, the three files, is because it is not clear to us (we only see the information you provide in your posts) if the form submits to the same page it is on (why is the line $_SESSION['nik'] = $_POST['nik']; on the form page) or if it submits to a different page. if you had shown us that the 2nd file is denetim.php, we could have the ignored that line of code setting the session variable on the form page. you changed the code on sayfam.php, which originally had that same line - $_SESSION['nik'] = $_POST['nik'];, which would have set the session variable to a null/empty value, because the post data only exists on the page the form submitted to. did you completely close your browser and start over after making that change to the code? next, here's a list of things you should/should not be doing - the login form processing code and the form should be on the same page. by putting them on separate pages, you are creating more work for yourself, in maintaining two pages. this also provides a bad user experience, since the use must now navigate back to the form page upon an error and depending on how you were going to display error messages on the form page, it makes your site open to a phishing attack. 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 piece of code that @Barand posted, checking the server request method, is the conditional logic that goes around the post method form processing. it insures that the form has been submitted before referencing any of the form data. don't copy variables to other variables for nothing. this is just a waste of your time typing. in the post method form processing code, keep the form data as a set, in an array variable, then operate on elements in this array variable throughout the rest of the code. you should trim all input data, mainly so that you can detect if all white-space characters were entered. you should validate all inputs before using them, storing user/validation errors in an array, using the field name as the main array index. after the end of the validation logic, if there are no user/validation errors, use the submitted form data. you should not store the plain-text password. use php's password_hash(), in the registration code, and password_verify() in the login code. don't put external/dynamic values directly into an sql query statement. use a prepared query instead. testing if $sonuc is a true value doesn't tell you if the query matched a row of data. it only tells you that the query executed without any error, and in fact in php8+, both the mysqli and PDO extensions use exceptions for errors and any conditional logic you have testing the returned value from a query is unnecessary and should be removed. if execution continues to the line following the execution of a query, you know that the query didn't produce an error. you must fetch and test the result of the fetch statement to know if a query matched any data. fetching the data is also necessary to use password_verify() and the value you store in the session variable upon successful login should be the user's id (autoincrement primary index), not the username. you should query on each page request to get any other user data, such as the username, user permissions, ... this insures that any change made to this use data will take effect on the very next page request after it was changed. the only redirect you should have upon successful login is to the exact same url of the form processing code. this will cause a get request for that page so that the browser won't attempt to resubmit the form data if that page is reloaded or navigated away from an back to. if you want to allow the user to go to a different page, provide navigation links. every redirect needs an exit/die statement after it to stop php code execution. a header() statement doesn't stop the php code from running. the session variable is an input to the code on a page. you must validate it before using it. if it is a 'required' input and it doesn't exist, that's an error. you would setup and display an error message instead of trying to use the session variable in the code. if it is not required, you would instead display a default value or skip displaying it at all.
  8. we can only help with specific programming questions. what exactly are you currently having a problem with? have you successfully used the month and dealerid inputs (which should be from a get method form) to query for the data that you want?
  9. this implementation has two problems. 1) by getting the existing value (wherever and whenever $rgy['mainbalance'] is being gotten and/or passed to/through the code), modifying it (wherever $newamount is coming from), then executing an update query, if there are concurrent operations on this data, they will all get the same starting value, modify it, then the last update query to be executed will replace any previously updated value. so, if for example there were two (or more) concurrent operations to subtract values, such as 1000 and 100, and the last update query to be executed is for the 100 value, then it would look like the 1000 value was never subtracted, leaving the wallet with a larger value in it then expected. if you continue to just update the value in a column (see the next point), you would modify the value completely within the update query, e.g. SET main = main - ? 2) by updating a value in a column, there is no audit-trail that would let you detect if a programming mistake, duplicate submission (hopefully you are using a run-once token for form submissions), or nefarious activity modified the value or let you produce statements/reports of who, what, when, where, and why the amount got changed. the correct way of doing this is to insert a new row of data into an accounting table for every transaction that affects the value. you would then simply SUM() the +/- amounts in a query whenever you need the current total, the same way that all your banking, credit card, loans, utility accounts, medical billing, ... do it. also, since the op didn't post all the code necessary to reproduce the problem (he was asked elsewhere for this), the values themselves could be determined from an external submission, rather than only being determined on the server.
  10. ids in the html markup must be unique. you cannot use id='anything' more than once and any javascript code using a static getElementById('anything') cannot be used. rather than showing non-working attempted code, show a couple of examples of server-side data and describe what operations you are trying to accomplish in the browser for that data.
  11. indexing/pivoting the data is a completely separate step. you need to build and execute the query (which isn't even attempting to use the dealer id, year, and month) to match the data that you want. index/pivot the data. then - edit: i recommend that you get up to the point of using print_r() on the indexed/pivoted data so that you can see what it is. this may give you an idea of what the code that produces the output will need to do.
  12. the key to converting row data into column output is to index/pivot the data using appropriate array index values when you fetch the data from the query. you would then loop over the indexed data, and for each row of data, loop over the expected column indexes, and test if there is data for the current column. if there's not, you would output an appropriate indicator value or an empty html table cell. if there is data, you would output the existing target value in the 'target' column and output the form field for the entry of the actual value in the 'actual' column. to index/pivot the data when you fetch it from the query, you would do something like this - $data = []; foreach($stmt as $row) { $data[$row['Description']][$row['Category_Name']] = $row; } you can examine what the result of doing this looks like using print_r($data). the form field names would NOT include the category_name as part of them. you would use an array field name, such as 'Actual', with the description value and the category_name value as the array indexes, e.g. - name="Actual[Rock Breaker][Excavator]" and as was pointed out in one of your previous threads - the point of DRY (Don't Repeat Yourself) code is to NOT write out , copy/paste/overtype, the same logic/markup for every possible value. you should be dynamically outputting things like the html table headings and the target/actual html table cells. to do this for the code in this thread, you would write out or query for an array of the category_name values for the columns. while you are doing that, you should also define the static parts of the target/actual heading text in variables, e.g. - $col = ['Excavator','Grader','Wheel Loader','SLM','Revenue']; $target_txt = 'Target in lakh'; $actual_txt = 'Actual in lakh'; once you do that, you can dynamically produce the html table headings - <?php foreach($col as $c) { echo "<th style='width:6%;'>$c $target_txt</th>"; echo "<th style='width:6%;'>$c $actual_txt</th>"; } ?> you would loop over the $col values again at the point of dynamically producing the target/actual html table cells.
  13. the error is (most likely) because you haven't validated ALL the inputs to your code before using them and because your schedule data is not properly stored. you should build any sql query statement in a php variable, so that you can echo it to see what it actually is. $_SESSION['shown_id'] is an input to your code. you must validate it before using it. if it isn't set, it means that there is no a current/selected teacher and all the code that's dependent on that value should not be executed. you would instead setup and display an error message letting the user know what's wrong and how to correct it. e.g. there's no current/selected teacher. either login or select a teacher. what does adding var_dump($_SESSION['shown_id']); show? if it's not set or it is not an expected value, you will need to find out why. you should have ONE table holding the schedule data for all the teachers, with a separate row for each teacher (faculty_number) , day, and period. there would only be rows for data that exists. as to the posted 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. the post method form processing should - 1) detect if a post method form was submitted, 2) keep the form data as a set, in an array variable, then operated on elements in this array variable throughout the rest of the code, 3) trim all the data at once, 4) validate all the form data, storing user/validation errors in an array using the field name as the main array index, 5) after the end of the validation logic, if there are no errors, use the form data, 6) after using the form data (which can produce more errors), if there are no errors, perform a redirect to the exact same url of the current page to cause a get request for that page. use 'require' for things your code must have for it to work. include/require are not functions. the () around the filename are unnecessary clutter and should be removed. don't copy variables to other variables for nothing. just use the original variables that data is in. for data fetched from a query, fetch it into a uniquely named array variable, then use elements in this array variable throughout the rest of the code. some major comments in your code, describing what each section is doing, would be helpful. e.g. get the name for the current/selected teacher, get the schedule for the current/selected teacher on the selected day and period, ... you would query the single schedule table, using a SELECT COUNT(*) ... query, to find if the selected substitute teacher (faculty_number) is available on the selected day and period. if this query doesn't match any data (the COUNT(*) term is zero), it means that the selected substitute teacher is not available. you would then query the single schedule table to get the row of data for the current/selected teacher (faculty_number) on the selected day and period, to build the sms message. you should use a prepared query any time you are supplying any dynamic value to the query when it gets executed. if using a prepared query with the mysqli extension seems overly complicated, this would be a good time to switch to the much simpler and more modern PDO extension. type='text/javascript' is no longer used in the <script> tag.
  14. don't bother with the mysqli extension. it is overly complicated, inconsistent, and in the case of procedural vs OOP statements, has different error responses for the same root problem. instead, use the much simpler, consistent, and more modern PDO extension. in php8+, both the mysqli and PDO extensions use exceptions for errors by default. the line of code that @Barand posted enables exceptions for errors for the msyqli extension. when you use exceptions for database statement errors, php will 'automatically' display or log the raw database errors, via an uncaught exception error. therefore, you can remove any existing error handling logic, since it won't ever get executed upon an error, simplifying the code. you should also name the connection variable as to the type of connection it contains, $mysqli/$pdo. this will let anyone looking at the code know what extension it is using, and also let you search for which code has been converted and which hasn't. you also need to use a prepared query when supplying external, unknown, dynamic values to a query when it gets executed, so that any sql special characters in a value cannot break the sql query syntax, which is how sql injection is accomplished. if you switch to the much simpler PDO extension, after you prepared the query, you can simply supply an array of the input values to the ->execute([...]) call.
  15. the database server must find the row(s) being update. it then reads the data in those row(s), for two main reasons - if a column value doesn't change, it doesn't write the data back to the disk, skipping an operation. the database server performs this comparison for you, using the current 'locked' values from the row, in one ATOMIC operation, so that you are not potentially comparing new values with 'stale' data that could have been changed by some other concurrent operation on the data. so that you can perform things like SET count = count + 1 ... in a single query
  16. ps, everyone on the same network will have the same ip address. if you are going to use a database based cart, you need to generate a unique value per visitor to use to identify each cart. the simplest way of doing this is to start a session, then use the session id as the identifier. pps, your cart should have a quantity column, so that someone could have more than one of each item.
  17. the only data you should be storing are the user entered values. the rest of the values (category total, row total, MS) are derived from the user entered data, and should not be stored. another reason to only process the user entered values is because data submitted to your site can come from anywhere, not just your forms/links, can be set to anything, and cannot be trusted. you must validate all data submitted to your site before using it and you must use it securely in whatever context it is being used in. therefore, you want to operate only on the necessary values. you should also NOT have a series of monthly columns in the table. you should have two tables. the first table gets a single row inserted with the unique (one-time) information about each set of data. the id (autoincrement primary index) from the first table would then be used in the second table to relate all the rows of monthly data back to the parent row in the first table. the second table would have columns for - id, parent id, either the month or the year-month, item id, and quantity. there would be one row in the second table for each non-zero quantity. your form processing code needs to be simplified and secured - don't copy variables to other variables for nothing, just use the original variables that data is in, use DRY coding, by looping over the $mon array of month abbreviations and dynamically access the form data, trim and validate all input data before using it, and use a prepared query, prepared once before the start of any looping, instead of putting values directly into the sql query statement.
  18. the point of DRY (Don't Repeat Yourself) code is to NOT write out , copy/paste/overtype, the same logic for every possible value. creating 12 variables and 12 copies of code is just taking up your time pushing keys on a keyboard. while you probably do need to (initially) calculate all the monthly column totals, you only need to calculate the current monthly column total for each input event. i recommend that you write a javascript function to do this for a dynamically specified column in the current tbody section. if you then need to calculate all the monthly column totals, you can loop over an array of the monthly class names to call the single column function 12 times. here's the version i came up with (this uses a different class naming for the total row) - // calculate the column total for a given month class name (mon) and the current tbody element (el) function calculate_col(mon,el) { var total = 0; var x; el.find('.'+mon).each(function () { x = parseInt($(this).val()); total += isNaN(x) ? 0 : x; }); el.find('.'+mon+'_Total').val(total); } to get the current month class name inside the input event handling logic - // get the current class attributes (a string) var classList = $(this).attr("class"); // split string on space characters var classArr = classList.split(/\s+/); // get the last element, the month class name var lastElement = classArr.pop(); calculate_col(lastElement,$(this).closest('tbody'));
  19. in order to produce the "total" row for each category section, you need separate sections. you can use separate tbodys for this. in order to detect when each category name changes, you need to remember the last category, then detect each time the value changes, to conditionally close out the previous section (only after a section has been output) and start a new section. this requires that you repeat the code to close out the previous section, at the end, to close the last section. as a simpler alternative, you can index/pivot the data from the query using the category name as the main array index, then use two nested foreach loops. since i/we don't know what other data you are selecting and using from that query, i didn't bother showing this. i also recommend that you dynamically produce any series of values, such as the month abbreviations and the output from them. this will result in DRY (Don't Repeat Yourself) code, where there's only one instance of the output written in the code, so that if you need to change or fix anything, you only have one place to make the changes. once you do that, you will end up with something that looks like this (tested only with some faked query data) - <?php // generate month labels foreach(range(1,12) as $m) { $mon[] = ucfirst(date('M',strtotime("2023-$m-01"))); } ?> <table style="margin-top:40px; height:15px" id="example" cellpadding="0" cellspacing="0" border="0" class="datatable table-sm table-hover table-striped table-bordered"> <thead> <tr> <?php $Year = date("y"); $previousYear = $Year - 1; ?> <th style="text-align:center; font-weight:bold;width:2%">S.No</th> <th style="text-align:center; font-weight:bold;width:10%">Category</th> <th style="text-align:center; font-weight:bold;width:10%">Model</th> <?php foreach($mon as $m) {?> <th style="text-align:center; font-weight:bold;width:4.5%"><?=$m.$previousYear?></th> <?php } ?> <th style="text-align:center; font-weight:bold;width:4.875%">Total</th> <th style="text-align:center; font-weight:bold;width:4.875%">MS %</th> </tr> </thead> <?php $qry=mysqli_query($conn,"SELECT * FROM model WHERE Brand_ID = '1' order by Category_Name ASC"); $n = 1; // remember last category, to detect when it changes $last_cat = ''; while($row = $qry->fetch_assoc()) { // detect if the category changed if($last_cat !== $row['Category_Name']) { // test if not the first output if($last_cat !== '') { // close the previous section - output a total row ?> <tr> <td colspan="2">&nbsp;</td> <td style="text-align:center">TOTAL</td> <?php foreach($mon as $m) {?> <td><input type="number" class="form-control <?=$m?>" name="<?=$m?>[]" style="width:100%" required></td> <?php } ?> <td><input type="number" name="Total[]" class="form-control cat_Total" style="width:100%" readonly></td> <td>&nbsp;</td> </tr> </tbody> <?php } // remember the new category $last_cat = $row['Category_Name']; // start a new section ?> <tbody> <?php } ?> <tr> <td align='center'><?=$n++?></td> <td style="text-align:center"><?=$row['Category_Name']?></td> <td style="text-align:center"><?=$row['Model_Name']?></td> <?php foreach($mon as $m) {?> <td><input type="number" class="form-control calc <?=$m?>" name="<?=$m?>[]" style="width:100%" required></td> <?php } ?> <td><input type="number" name="Total[]" class="form-control Total" style="width:100%" readonly></td> <td><input type="number" name="MS[]" class="form-control MS" style="width:100%" readonly></td> </tr> <?php } // end of data loop // if there was any output, close out the last section if($last_cat !== '') { // close the previous section - output a total row ?> <tr> <td colspan="2">&nbsp;</td> <td style="text-align:center">TOTAL</td> <?php foreach($mon as $m) {?> <td><input type="number" class="form-control <?=$m?>" name="<?=$m?>[]" style="width:100%" required></td> <?php } ?> <td><input type="number" name="Total[]" class="form-control cat_Total" style="width:100%" readonly></td> <td>&nbsp;</td> </tr> </tbody> <?php } ?> </table> note: you cannot use the % character in field names or css class names. this example uses just 'MS' in these cases. once you do that, the javascript (not including each month's column total) becomes - <script> $(document).ready(function () { $(".calc").on('input', function () { var row_total = 0; var cat_total = 0; var x; var ms; // current row total $(this).closest('tr').find('.calc').each(function () { x = parseInt($(this).val()); row_total += isNaN(x) ? 0 : x; }); $(this).closest('tr').find('.Total').val(row_total); // category total $(this).closest('tbody').find('.Total').each(function () { x = parseInt($(this).val()); cat_total += isNaN(x) ? 0 : x; }); $(this).closest('tbody').find('.cat_Total').val(cat_total); // ms calc = each row total/cat_Total * 100 $(this).closest('tbody').find('.Total').each(function (index) { x = parseInt($(this).val()); ms = (isNaN(x) ? 0 : x)/cat_total*100; $(this).closest('tbody').find('.MS').eq(index).val(ms.toFixed(2)); }); }); }); </script>
  20. the example you are using is actually from the link that @maxxd posted this is using the PDO extension. did you change your connection code to use the PDO extension? you would be getting a fatal runtime error if you didn't. this can actually be further simplified by using FIND_IN_SET() or NOT FIND_IN_SET(), for the query you are showing us, and using a single prepared query place-holder. the code you posted is fetching all the matching rows of data into $a_data. it is this variable that you would test/loop over to produce the output in the html document. if you set the default fetch mode to assoc when you make the PDO connection, you don't need to specify it in each fetch statement, simplifying the code. the only time you should handle database statement exceptions in your code are for user recoverable errors, such as when inserting/updating duplicate or out of range data. in all other cases, simply do nothing in your code and let php handle the exception, simplifying the code.
  21. all of this code is unnecessary. you can use php's ... operator. see the Argument unpacking via ... example at this link - https://www.php.net/manual/en/migration56.new-features.php
  22. after you have made a connection using the PDO extension, in a variable named $pdo (so that anyone looking at the code will get a hint at which extension it is using), the database specific code would be - // prepare the query. this returns a PDOStatment object, hence the variable named $stmt $stmt = $pdo->prepare($query); // execute the query, supplying an array of input values to the ->execute() call that correspond to the positional ? place-holders in the sql query statement $stmt->execute([$from, $to]); at the point of fetching the data from the query - while($row = $stmt->fetch()) { // use elements in $row, e.g. $row['employee_name'] } typical PDO connection code - $DB_HOST = ''; // database host name or ip address $DB_USER = ''; // database username $DB_PASS = ''; // database password $DB_NAME = ''; // database name $DB_ENCODING = 'utf8mb4'; // db character encoding. set to match your database table's character set. note: utf8 is an alias of utf8mb3/utf8mb4 $options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // set the error mode to exceptions (this is now the default in php8+) PDO::ATTR_EMULATE_PREPARES => false, // run real prepared queries PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC // set default fetch mode to assoc, so that you don't need to specify it in each fetch statement ]; $pdo = new pdo("mysql:host=$DB_HOST;dbname=$DB_NAME;charset=$DB_ENCODING",$DB_USER,$DB_PASS,$options);
  23. this might be a good time to switch to the much simpler and more modern PDO extension. you can simply and directly fetch and use data from a prepared query in the same way as for a non-prepared query.
  24. 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.
  25. 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.
×
×
  • 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.