-
Posts
5,507 -
Joined
-
Days Won
185
Everything posted by mac_gyver
-
Php Require or Include inside of IF/ELSE statement
mac_gyver replied to meOmy's topic in PHP Coding Help
this is nonsense code that has been floating around on the web for a long time. the only thing it is doing that is proper is trimming the value. stripslashes, when it was needed, should have been conditionally applied only when magic_quotes_gpc was on, but the (bad) feature in php that needed stripslashes to be applied to input data was removed from php in 2012, over a decade ago. htmlspecialchars is an output function. it is applied to data being used in a html context. it is not used on input data that your script will use for database operations as it modifies the value. so, even if this function only trimmed the data, the proper place to use it would have been before validating the data, so that you would be validating the trimmed values. -
Php Require or Include inside of IF/ELSE statement
mac_gyver replied to meOmy's topic in PHP Coding Help
because you have no logic to do this. the else() you have is part of the last if(){} conditional, for the phone number. you should NOT use discrete variables for the error messages. this would require you to either have an additional flag to indicate any errors or you would need to write a conditional test with all the discrete variables. you should instead use an array (arrays are for sets of things where you are going to operate on each member in the set in the same or similar way) to hold the user/validation errors, using the field name as the main array index. after the end of the validation logic, if the array holding the errors is empty, you can use the submitted form data, e.g. - if(empty($errors)) { // use the submitted data here... } to display the errors at the appropriate location in the html document, either test the contents of the array and display all the errors together or display each error adjacent to the field it corresponds to. speaking of/writing about using arrays for sets of things, you should keep the form data as a set in a php array variable, then operate on elements in this array variable throughput the rest of the code. this will allow you to trim all the data at once, using one php array function, and will support dynamically validating and processing the data. speaking of/writing about dynamically validating the data, you should NOT write out - copy/paste logic for every possible value. you should instead use a data-driven design, where you have a data structure (database table, array) that holds the dynamic values, then use this definition to control what general purpose logic does. the only thing that is different between these validation types is the regex pattern. why not store them in an array with the data type, regex pattern and error message, then just get the correct entry and call one general purpose function with the correct type regex pattern and the input value? whatever the code is for this function is probably improper. in general, besides trimming input data, you should NOT modify user submitted data as this changes the meaning of the data. if data is valid, use it. if it is not, tell the user what is wrong with it and let the user fix then resubmit the data. -
here's even more issues - the email column should be defined as a unique index. this will prevent duplicate email addresses, which could be the cause of the current symptom. then, in the registration code, the exception error handling for the INSERT query would test for a duplicate index error number, and setup a message that the email address is already in use. when you make the database connection, you need to set the character set to match your database table's character set, so that no character conversion occurs over the connection. this is doubly important when using emulated prepared queries, which you are using but which should be avoided whenever possible, so that sql special characters in a value won't be able to break the sql query syntax. when you make the database connection, you should set the emulated prepared query setting to false, i.e. you want to use true prepared queries whenever possible. when you make the database connection, you should set the default fetch mode to assoc, so that you only get the type of fetched data that you want and so that you don't need to specify the fetch mode in each fetch statement.
-
@LeonLatex, because you haven't posted the registration and login forms (you could have a typo between the field names and the php code), aren't trimming and validating the inputs before using them (any of the inputs could be empty or contain additional characters due to typo mistakes or something javascript is adding) , and have lumped together the test for the user row and password_verfy() (you currently have no single place to test if a user row was not found, then if the password_hash() didn't match), no one here can determine why this isn't working. you could also be overwriting the $password variable if your actual code is requiring the database connection code right before executing the query. edit: here's another couple of problems with the form processing code you have posted. you should only store the user_id in a session variable, then query on each page request to get any other user data, such as permissions/roles, so that any change in these other values will take effect on the very next page request after they have been changed. the redirect should be to the exact same URL of the current page to cause a get request to be registered in the browser for that URL. by redirecting to a different URL, anyone can walk up to a computer that was used to register/login using this code and browse back to the form page, which will cause the browser to resubmit the form data, where you can use the browser's developer console network tab to see what the submitted form data is.
-
@Phi11W, password_hash() produces a different hash for the same input, every time it is called, because it generates a random salt each time it is called. this is precisely why password_verify() must be used. it takes the algorithm, cost and salt from the existing hashed value, hashes the submitted password using these values, then compares the resulting hash of the submitted value with the existing hashed value.
-
where is the error being generated at or seen at? i suspect is it a php error message being displayed in the 'chat' output? the reason it may appear differently is because it contains html markup, which may or may not get rendered by the browser. out of memory errors as usually caused by logic that either has an initial condition problem, where an assumption being made isn't satisfied, or a loop that runs forever and keeps adding data until all memory is consumed, without removing older data.
-
you should not modify data, then use the modified value, as this changes the meaning of the data (ask the author's of this forum software about the email 'cleaning' they did a number of years ago that allowed hackers to create a real and valid email addresses that was similar to an administrator's, that after 'cleaning' allowed it to be used to do a password recovery for that administrator, and allowed the hackers to log in as that administrator.) you should only trim user submitted data, mainly so that you can detect if it was all white-space characters, then validate that the trimmed value meets the 'business' needs of your application. if the data is valid, use it securely in whatever context it is being used in. if the data is not valid, tell the user what was wrong with the data and let them correct and resubmit it.
-
the above only produces a php warning if $conn is a false value. it also results in a false value for the if() conditional test, which looks like a connection without an error (this is yet another f___ up with the mysqli extension implementation.) it is also due to the different error responses between procedural mysqli and oop mysqli statements. you should be using exceptions for database statement errors (this is the default setting now in php8+) and in most cases simply do nothing else in your code and let php handle any database exception, where php will use its error related settings to control what happens with the actual error information, via an uncaught exception error (database statement errors will 'automatically' get displayed/logged the same as php errors.) you can then eliminate all the existing error handling logic, since it won't get executed upon an error, simplifying your code. a) you need to set php's error_reporting to E_ALL and display_errors to ON, preferably in the php.ini on your development system, so that php will help you by reporting and displaying all the errors it detects. stop and start your web server to get any changes made to the php.ini to take effect and use a phpinfo() statement in a .php scrip to confirm that the settings actually took effect. b) you should be using php8+. c) to use exceptions for the mysqli extension in older versions of php, add the following line of code before the point where you make the database connection - mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
-
From the documentation - it seems like you should be using an UPDATE query for this operation?
-
if you had properly stored your data as has been previously suggested in your threads, with date and amount columns and a row for each piece of data, this would be a simple task that could be accomplished in a straight-forward sql query. but because you have a year column and separate month name columns, your code must take the year and month from the 'from' and 'to' values and figure out which rows and which columns to use to calculate the result.
-
PHP MYSQL Insert Array on Same Table Row
mac_gyver replied to experience40's topic in PHP Coding Help
to normalize this data, you need an attribute table, with - id (autoincrement primary index) and name columns. as new attributes are defined, they would be inserted into this table. this table establishes attribute ids. the map table would map the csv column number to these attribute ids. you would JOIN with this table when displaying information to get the meaningful names for each attribute id. the stock table would not be laid out as a spreadsheet. you would instead insert only the unique one-time information for each item into the stock table. this would establish a stock id for each item for each user/feed. you would then have a stock attribute table with - id (autoincrement primary index), stock id, attribute id, and value columns. you would insert a separate row into the the stock attribute table for each csv column value for each stock id. when you are inserting the data, you would query the map table to get the set of rows for the user/feed and fetch these into an array. when you read each row of data from the csv file, you would then loop over this array of map data, use the csv column number to get the data value from the row of csv data, then use this data value and the attribute id for executing the stock attribute insert query. -
Display search result by joining tables in php
mac_gyver replied to johnman's topic in PHP Coding Help
the following is the syntax definition for a SELECT query - 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 relevant parts that you need for this query are - SELECT select_expr , select_expr ... FROM table_references WHERE where_condition ORDER BY {col_name | expr | position} [ASC | DESC], ... you should list out the columns you are selecting, i.e. don't use * there would only be one FROM keyword in this particular query. the table_references section is where the JOIN part of the query goes. the where_condition would contain the columns, comparison operators, and prepared query place-holders for the brand and location matching. almost every query that can return a set of rows should have an ORDER BY ... term so that the result is in a desired order. the existing sql statement should be producing a query error and probably php errors. you should use exceptions for database statement errors (which is the default now in php8+) and in most cases simply let php catch and handle the exception, where php will use its error related settings to control what happens with the actual error information (database statement errors will 'automatically' get displayed/logged the same as php errors.) you would set the PDO error mode to exceptions when you make the database connection. you should also set emulated prepared queries to false, so that you use true prepared queries. do you have php's error_reporting set to E_ALL and display_errors set to ON, preferably in the php.ini on your development system, so that php will report and display all the errors it detects (which will now include database statement errors)? as to the rest of the code - the form processing and form should be on the same page. this will result in the least amount of code and provide the best user experience. 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. you need to validate the resulting web pages at validator.w3.org don't prepare and execute a non-prepared query. just use the ->query() method. if you set the default fetch mode when you make the database connection, you won't need to specify it in each fetch statement. don't use the ->rowCount() method. it is not guaranteed to work with SELECT queries. since you have fetched all the rows of data from the query into a php variable, you can just test that variable to determine if the the query matched any rows. for the required attribute to work for a select/option menu, the value attribute for the 1st option/prompt choice must be an empty string (the w3.org validator will point out this problem.) the form should be 'sticky' and re-select the option choices that match any existing search data, so that if the search doesn't match things the user is interested in, the user can just make a different selection and resubmit the form. in the location query, listing the column name twice does nothing. you only need to specify the column name once in the query. you can reference it as many times are you want in the result set. if you put the label tags around (before/after) the field they belong with, you can eliminate the for='...' and corresponding id='...' attributes, which will eliminate more of the markup errors (ids must be unique.) if you use implicit binding, by suppling an array of values to the ->execute([...]) call, you can eliminate the bindParam() statements. if you use simple positional prepared query place-holders ?, you can eliminate the repetitive typing of place-holder names in the query and php code. -
While with foreach not giving correct value
mac_gyver replied to Adamhumbug's topic in PHP Coding Help
the way to correct and simplify this is to - this will eliminate all the sumOpenAndAcceptedValueByClient() usage. the single query will give you the quote total (accepted and open) and open total (open only) values per client_id. you would then just use those values as you are looping to produce the output. i hope you are not doing this in every function that needs a database connection? this is creating multiple database connections per instance of your script and a database connection is one of the slowest operations you can perform. your main code should create one database connection, then supply it to any function that needs it as a call-time parameter. you should also use 'require' for things that your code must have for it to work. if you eliminate all the bindColumn() statements and just fetch each row into $row, you would reference each column value as $row['column_name'], which is probably how the code was originally written. this will also eliminate the multiple different names you are using for the same meaning data. the id/client_id will never be null from this query since it is from the primary table. this conditional test is unnecessary. -
this is just indexing/pivoting the data by a column. PDO has a fetch mode that will 'automatically' do that for you, assuming that the sectionName is the first column in the SELECT ... list - $data = $stmt -> fetchAll(PDO::FETCH_GROUP); if for some reason you require the name values to be referenced as itemName in the fetched data, assign it that name as an alias in the sql query.
-
On duplicate key update always inserting new row
mac_gyver replied to Adamhumbug's topic in MySQL Help
the place-holder mismatch will work using emulated prepared queries (which should be avoided whenever possible), but not for true prepared queries. the emulator is more of an approximator, because there are differences that you can detect between how it works vs a true prepared query. -
Function runs great when called isolated but only that way
mac_gyver replied to Javiigahe's topic in PHP Coding Help
the user table would hold the common one-time information. you would have a second table holding the unique information for the different types of users, with a separate row for each piece of information, related back to the user table through the user id. -
Function runs great when called isolated but only that way
mac_gyver replied to Javiigahe's topic in PHP Coding Help
the problem is you are using the $password variable for two different things. 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 you should have one user database table with both client and psychologist registration/login data and a 'type' column holding a value that indicates which type of user they are. Don't Repeat Yourself (DRY.) it is not the responsibility of the sendOTPmail() function to create a database connection. you already have a database connection in the application, supply it to any function that needs it as a call-time parameter. -
While with foreach not giving correct value
mac_gyver replied to Adamhumbug's topic in PHP Coding Help
what's the difference between accepted and open and why doesn't the first query use accepted = 1 too? i'm betting that the $out = ""; variable in the first posted code is being used to build the output in the image, listing the results by the left-hand ranges (guessing per client), and the echo statements are just there for debugging? this is going to be a case of - don't show us your non-working attempt and expect us to figure out what's wrong, instead show us sample data and what result you expect from that data. also - don't waste your time with bindColumn() statements, this is wasted typing. just fetch the data and reference the data by its associative index (column) name. lastly, why are you preparing a non-prepared query that doesn't have any values being supplied to it? just directly use the ->query() method. -
while there probably is a way of doing this in a query, with a sub-query/self-join, i would just perform the calculation when you produce the output.
-
you would add GROUP BY client.id to the query to get a SUM() per client. in fact, if your database was set to STRICT mode, you would be getting an error with the current query about using an aggerate function without a GROUP BY term. then, if you want both the SUM() per client and the grand total, you can add WITH ROLLUP to the end of the GROUP BY ... term.
-
change the value of ID of newest group of fields
mac_gyver replied to jasonc310771's topic in Javascript Help
client-side validation is a nicety for legitimate visitors. since you must validate the data on the server before using it, why go to all this trouble to duplicate the logic in the client that you (already) have in the server-side code? and if you want to pre-validate the data in the client, why not just send the relevant data values to the server using ajax, run it through the (existing) validation logic, and display the result returned by that validation logic? -
change the value of ID of newest group of fields
mac_gyver replied to jasonc310771's topic in Javascript Help
what item? we cannot help you unless you post the complete code the reproduces the problem. in programming, there are just too many different ways of accomplishing a task. it takes knowing how you go to a point, in order to help you. -
change the value of ID of newest group of fields
mac_gyver replied to jasonc310771's topic in Javascript Help
you would use the same method that the 'add more click' function is using, of starting with the current element (this) and using tree traversal methods with class selectors to navigate around in the DOM - https://api.jquery.com/category/traversing/tree-traversal/ -
this javascript was apparently part of a php echo statement at one time, since it is trying to concatenate $row['id'] inside a double-quoted string. you cannot just take something that was in a php context and use it by itself without reading what it is doing and modify it appropriately. before you can use ajax to make a http request, you must be able to design, write, test, and debug the html and php to accomplish the task. you will need most of the same code and that code must be secure, provide a good user experience, and contain error handling and validation logic so that it will either work or it will tell you why it doesn't, since adding ajax adds a layer on top of everything that makes debugging harder. next, the point of using a post method form/request when performing an action on the server, is so that a search engine indexing a site won't trigger those actions. the post method form processing code (regardless of using ajax or not) should - detect if a post method form was submitted before referencing any of the form data only use $_POST data enforce user 'delete' permission and data ownership/administrator-ship to control who can delete data trim, then validate all input data before using it use a prepared query so that any sql special characters in a value cannot break the sql query syntax, which is how sql injection is accomplished. to accomplish item #2 on this list, you would use a hidden field in the form for the $row['id'] value. this is the point of the ajax data being set to the form's data - data: $(this).serialize()
-
if you are not posting the actual code that you are having a problem with, the replies you get may not have anything to do with the problem. here's example code (tested with faked data from the SELECT query) showing most of the points that i made - <?php // initialization // recursive trim function function _trim($val) { if(is_array($val)) { return array_map('_trim',$val); } else { return trim($val); } } session_start(); // make database connection here... $table_name = 'your_table'; $error = []; // an array to hold user/validation errors $post = []; // an array to hold a trimmed working copy of the form data // get all subject data $sql = "SELECT id, subject_name FROM tbl_subjects_secondary"; $stmt=$pdo->query($sql); $subject_data = $stmt->fetchAll(); // post method form processing if($_SERVER['REQUEST_METHOD'] === 'POST') { // trim all the input data at once $post = _trim($_POST); // loop over the subject ids and validate the corresponding form data foreach(array_column($subject_data,'id') as $key) { if($post['test_score'][$key] === '') { $error['test_score'][$key] = "Test Score Field is Required"; } if($post['exam_score'][$key] === '') { $error['exam_score'][$key] = "Exam Score Field is Required"; } } // if no errors, use the submitted data if(empty($error)) { $sql = "INSERT INTO $table_name ( subject_id, test_score, exam_score ) VALUES ( ?, ?, ? )"; $stmt = $pdo->prepare($sql); foreach(array_column($subject_data,'id') as $key) { $stmt->execute([ $key, $post['test_score'][$key], $post['exam_score'][$key] ]); // note: error handling for this query is not included with this example code } } // if no errors, success if(empty($error)) { // 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 inserted the subject scores'; // redirect to the exact same url of the current page to cause a get request - PRG Post, Redirect, Get. die(header("Refresh:0")); } } // get method business logic - get/produce data needed to display the page // get all subject data - located above the post method form processing since it is also used by the validation logic // html document ?> <!DOCTYPE html> <html lang="en-US"> <head> <meta charset="utf-8"> <title>Multi-row Insert Example</title> </head> <body> <?php // display and clear any success message if(isset($_SESSION['success_message'])) { echo '<p>'.$_SESSION['success_message'].'</p>';; unset($_SESSION['success_message']); } ?> <?php // display the form ?> <form method="post"> <table class="table table-borderless"> <thead> <tr> <th>SN</th> <th>Subject</th> <th>Continuous Assessment Score</th> <th>Examination Score</th> </tr> </thead> <tbody> <?php $i = 1; foreach($subject_data as $row) { ?> <tr> <th><?= $i++ ?></th> <td><input type="text" class="form-control border-0" readonly value="<?=$row['subject_name']?>"></td> <td><input type="number" name="test_score[<?=$row['id']?>]" class="form-control" value="<?=htmlentities($post['test_score'][$row['id']]??'',ENT_QUOTES)?>"><span style="color: red; font-size: .8em;"><?= $error['test_score'][$row['id']]??'' ?></span></td> <td><input type="number" name="exam_score[<?=$row['id']?>]" class="form-control" value="<?=htmlentities($post['exam_score'][$row['id']]??'',ENT_QUOTES)?>"><span style="color: red; font-size: .8em;"><?= $error['exam_score'][$row['id']]??'' ?></span></td> </tr> <?php } ?> <tr> <td></td><td></td> <td colspan="2"><button type="submit" class="btn btn-primary w-50">Save</button></td> </tr> </tbody> </table> </form> </body> </html> this produces valid markup, validation per field, and repopulates the field values upon a validation error.