-
Posts
5,450 -
Joined
-
Days Won
175
Everything posted by mac_gyver
-
at about line 105 in Statement.php is a short opening tag.
-
you are seeing the raw php code in the browser because of the short opening <? tag. always use full opening <?php tags. you should not make a new database connection in every function. your main code should make one database connection, then supply it as a call-time parameter to any function that needs it. if doing this requires too much restructuring of the existing code, the connectDB() function should define a static variable to hold the connection, then test for and only make a new connection if there is not already one. the default setting in php8+ for PDO errors is to use exceptions for all the database statements that can fail. you should only catch and handle database exceptions for user recoverable errors, such as when inserting/updating duplicate or out of range data. in all other cases, simply let php catch and handle any database exceptions, where php will use its error related settings to control what happens with the actual error information, via an uncaught exception error (database statement errors will 'automatically' get displayed/logged the same as php errors.)
-
when you successfully complete the post method form processing code, you should perform a redirect to the exact same URL of the current page, the page the form processing code and the form is on, to cause a get request for that page. this is called - Post, Redirect, Get (PRG) - https://en.wikipedia.org/wiki/Post/Redirect/Get this will prevent the browser from resubmitting the form data should that page get reloaded or browsed away from and back to. to display a one-time success message/content, store a value in a session variable, then test for the session variable, display the variable/content, and clear that session variable, at the appropriate location in the html document on that page. to allow the visitor to go to any other page, provide navigation links.
-
Why does it yield empty string in the database?
mac_gyver replied to watsonjohn's topic in PHP Coding Help
form fields need a name="..." attribute, e.g. name="firstname", ... if you are just starting out, forget about using the overly complicated and inconsistent mysqli extension. instead, use the much simpler and more modern PDO extension, and use prepared queries. you should also put the form and form processing code on the same page, as this results in the simplest code. the code for any page should be laid out in this general order - 1) initialization, 2) post method form processing, 3) get method business logic - get/produce data needed to display the page, 4) html document. -
Want to reduce the repeating code on my php filter query
mac_gyver replied to SrilekhaRamesh's topic in PHP Coding Help
1st of all, all the post data you send in the request will be set (is_category, sales, material, salesoffice), so there's no point in testing if it is set, because it will be. if using a post request, just detect if the REQUEST_METHOD is 'POST' you should actually be using a get method request when determining what will be displayed on a page. while I'm pretty sure this has already been covered in a previous thread, you should be using a data-driven design (which is probably what the $column array is part of.) so what are you actually trying to accomplish? include a column/value in the WHERE clause if there is a non-empty value for that input? to do this, you don't need to write out code for every possible combination. regardless of using a data-driven design or conditional logic (once) for each input, you only need code that includes a column/value if there is a non empty value for that input. // using a data-driven design, define permitted WHERE columns and corresponding inputs $where_columns = ['sales_doc_type'=>'sales', 'material'=>'material', 'sales_office'=>'salesoffice']; // array to hold where terms $where_terms = []; // array to hold prepared query input parameters $params = []; // build the where terms foreach($where_columns as $col=>$input) { if($_POST[$input] ==! '') { $where_terms[] = "`$col`=?"; $params[] = "$_POST[$input]"; } } // build the WHERE clause $where = ''; if(!empty($where_terms)) { $where = 'WHERE ' . implode(' AND ',$where_terms); } // build the sql query $sql = "SELECT * FROM billing $where"; // examine the result echo $sql; echo '<pre>'; print_r($params); echo '</pre>'; -
PHP Get Maximum Value From DB and Set Start Value for Loop
mac_gyver replied to experience40's topic in PHP Coding Help
getting the current highest MAX() value and incrementing it in your code is not concurrent safe. if there are multiple instances of your script running at the same time (you must assume that this is possible), they will all get the same starting value, resulting in duplicate ids. the correct way of doing this is to have a table with an autoincrement primary index, insert a row of 'main' data, get the last insert id from that query and use it when inserting the data related to each 'main' row of data. -
once you switch to using a .csv file, you need to use a data-driven design, where you simply define a data structure (array) that controls what general purpose code does. see the following (untested, but should work) example - <?php /* data used - [0] => Sales Document Type [2] => Billing Date [11] => Material [25] => Gross Amount [45] => Sales Office [47] => Plant */ /* note: if you insure that the order in the following definition matches the order in the data file, you can use the array intersection method in the following code. otherwise, you must use the (commented out) loop method in the following code. */ // define mapping of data index to database column $db_col = [0=>'Sales_Document_Type', 2=>'Billing_Date', 11=>'Material', 25=>'Gross_Amount', 45=>'Sales_Office', 47=>'Plant']; // database table name $table = 'billing'; // number of initial lines to skip in the file $skip = 1; // for demonstration purposes, the file is hard-coded to be the converted csv of the example . xlsx file // in the actual code, this would be set to the temporary uploaded file $file = 'Aug Spares.XLSX - Sheet1.csv'; // open file if (($handle = fopen($file, "r")) !== FALSE) { // dynamically build the sql query $sql = "INSERT INTO `$table` (`".implode('`,`',array_values($db_col))."`) VALUES (".implode(',',array_fill(0,count($db_col),'?')).")"; // this example uses the much simpler and more modern PDO database extension $stmt = $pdo->prepare($sql); // start line counter at 1 $line = 1; // read lines from file while (($row = fgetcsv($handle, 1000, ",")) !== FALSE) { // process lines after initial skipped lines if($line > $skip) { // special processing // convert Billing_Date to standard format $row[2] = date('Y-m-d', strtotime($row[2])); // remove comma separator from Gross_Amount $row[25] = str_replace(',', '', $row[25]); // build array of value using array intersection method $params = array_values(array_intersect_key($row,$db_col)); /* // build array of values using a loop $params = []; foreach(array_keys($db_col) as $key) { $params[] = $row[$key]; } */ $stmt->execute($params); } $line++; } fclose($handle); } else { die('unable to open uploaded (temporary) file'); }
-
Error: Could not create team. Column 'manager_id' cannot be null
mac_gyver replied to Realest89's topic in PHP Coding Help
the session variable is a 'required' input to your code. you must 'validate' it before using it, i.e. the current user must be logged in, in order to be able to see the team creation form and process the form data. if there is not a logged in user, you must take an appropriate action and not allow the current user to see the form or be able to run the form processing code. next, the only piece of user data you should store in a session variable upon successful login is the user_id. you should query on each page request to get any other user data, such as the username. this will allow this other user data to be edited and the change will take effect on the very next page request. likewise, you should not store the username in the players table. this is duplicating data that's defined/stored elsewhere. if you have the player's user_id, you would query when needed to get the player's username. if you were doing this for real, you would need to run the set of INSERT queries as part of a transaction, so that if either query failed with an error, they can both be rolled back. you also need to define the teams teamname and tag columns as unique indexes, to prevent duplicates, and have error handling that tests the result of the teams insert query for a duplicate index error (number.) the players userid and team_id columns must be defined as a composite unique index, to prevent duplicates (assuming that a player can only be on one team at a time), and have error handling that tests the result of the players insert query for a duplicate index error (number.) -
nested forms are invalid. what is the form markup? only checked checkboxes are included in the submitted form data. since you are using $row['CODE'] as the checkbox's array name index, that's all you need. you would just get and use the array indexes inside the post method form processing code. the checkboxes are the only valid form fields in the posted code. the rest of that isn't valid, but isn't needed anyways. you should only display the cost on the web page. you should not pass the cost through the web page, where it can be manipulated and be set to anything. you should get the cost in the post method form processing code if you need it. you would only store the cost with the selected items if the cost can change over time and you haven't setup a table to hold the cost history data. you don't need id attributes in the markup unless you are referencing the individual elements in the browser. ids must also be unique, therefore the use of the same id='CODE' and id='COST' inside the loop doesn't work properly. the post method form processing should detect is a post method form was submitted, before referencing any of the form data.
-
the message you cited occurs when you do a 'view source' of the page in the browser. any get parameters you have in the URL should only determine what content is gotten and displayed on the page, not what post method form action is performed in the server-side code. if the last request the browser has for a URL is a html post method form submission, the form data will get resubmitted when you do a 'view source' of the page (even if you have prevented the form itself from being redisplayed on that page.) your first post in this thread indicated that you know you could use ajax, not that you were already using it. the reply you got is based on how you would normally do this, using a html post method form submitted to server-side post method form processing code, on the same page, to prevent the browser from trying to resubmit the post method form data should that page get reloaded, a 'view source' performed on it, or the URL is browsed away from and back to, by instructing the browser to perform a get request for the exact (including any existing get parameters) same URL of the current page. the main point of using ajax on a web page is so that you don't reload the whole page. if what you are doing means that you are going to reload the whole page anyways, you shouldn't be using ajax to do this. when you do use ajax to submit a post method form, the ajax response code needs to deal with any server-side success/failure response (validation errors, duplicate data errors, ...) that are produced and output by the server-side code.
-
PDO::__construct(): Server sent charset (255) unknown to the client
mac_gyver replied to Digger's topic in PHP Coding Help
upon searching, this is due to the MySql server reporting a value back to the client (php in this case) that php doesn't recognize for the character set setting. is this just an error that is getting logged or does it prevent the connection from being used? here's a bug report that suggests a work-around of setting a character-set-server value in the MySql's my.cnf - https://bugs.mysql.com/bug.php?id=85946 -
PDO::__construct(): Server sent charset (255) unknown to the client
mac_gyver replied to Digger's topic in PHP Coding Help
try using utf8mb4 for the setting. utf8 is (was) an alias for utf8mb4, which i'm guessing is no longer valid. -
PHP 8.2 - mysqli_report(MYSQLI_REPORT_OFF) doesn't work
mac_gyver replied to Zeux's topic in PHP Coding Help
you have jumped to an incorrect conclusion about what is occurring. an sql query that has no programming mistake doesn't produce any php errors when accessing the result from that query, regardless of php version. you are getting php errors because there's something wrong with the specific sql query in question with the code you are posting. if you do what has already been suggested and add error handling, you can find out what is wrong with the query. if you want anyone here to help, you will need to post the sql query. i'm going to guess that you are putting a value, in a php variable, directly into the sql query statement, in a numerical context, such as an id, but the value is empty, resulting in an sql syntax error. this is a programming mistake. the correct way to fix this is to validate inputs, only execute a query when 'required' inputs have an expected value, and to use a prepared query so that any sql special characters in a value cannot break the sql query syntax. -
PHP 8.2 - mysqli_report(MYSQLI_REPORT_OFF) doesn't work
mac_gyver replied to Zeux's topic in PHP Coding Help
this code is attempting to test the number of rows in a result set for a successful (no execution error) query. (you should actually just fetch the data and test if there was fetched data, since you want to use the data if it exists, simplifying the code.) the php errors you are getting mean that the query didn't execute at all, due to things like an sql syntax error, wrong database or no database selected, incorrect table or column names, incorrect use of aggerate functions, ... having error handling for the database statements that can fail, will mean that this code, testing the number of rows in a result set, will only get executed if the query executed successfully, without errors. this is one of the great points of using exceptions for error handling. your main code will only see and deal with error free execution of statements that can throw exceptions, since execution transfers to the nearest correct type of exception handling upon an error or to php if there is no correct type exception handling in your code. -
PHP 8.2 - mysqli_report(MYSQLI_REPORT_OFF) doesn't work
mac_gyver replied to Zeux's topic in PHP Coding Help
the error you are getting is a follow-on error, because there was no error handling at the query() call that failed, and the code continued to run and tried to use the a result that doesn't exist. you ALWAYS need error handling for statements that can fail. for database statements that can fail - connection, query, exec, prepare, and execute, the SIMPLEST way of adding error handling, without adding logic at each statement, is to use exceptions for errors 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.) the exception to this rule is when inserting/updating duplicate or out of range user submitted data. in this case, your code should catch the exception, test if the error number is for something that your code is designed to handle, then setup a message telling the user what was wrong with the data that they submitted. for all other error numbers, just re-throw the exception and let php handle it. by turning off exceptions for the mysqli error handling, you must now handle errors for each of these statements, which means you must write conditional logic testing the result from each statement call and take an appropriate action, such as preventing the following code from being executed if a statement call failed. -
while these points probably have nothing to do with the performance problem (with the exception of the invalidate markup), the code needs to be refactored, corrected, simplified, and cleaned up - this code is filled with unnecessary copying of variables to other variables and repetitive code that only differs in a variable name/title. just use the original variables that data is in and use a template/function/data-driven design instead of writing out code for every value. you want to always report all php errors. when learning, developing, and debugging, you want to display all php errors. when on a live/public server, you want to log all php errors. the error related settings should be in the php.ini on your system, so that you can set or change them at a single place. use 'require' for things your code must have for it to work and be consistent in what you use. include/require are not functions. the () around the file name do nothing. leave them out. the session variable with the user id should either be set and contain the id or it should not be set. don't bother testing if it is an empty string. it should never be one. many things have have ids. the session variable holding the user id should be uniquely named, something like user_id. there's no good reason to destroy the whole session. a session can contain more than just the logged in user's id. all inputs need to be trimmed, then validated before being used. if 'required' input(s) are not valid, don't run the code that's dependent upon them. every redirect needs an exit/die statement to stop php code execution. currently, all the code on the page runs, even if there is no logged in user. don't use or die(...) for error handling. use exceptions for database statement error handling (which is the default setting now in php8+) and in most cases simply let php catch and handle any database exception. mysqli_error() requires the connection variable as a parameter. this problem will go away when you switch to using exceptions for database errors. use a prepared query when supplying external, unknown, dynamic values to a sql query when it gets executed. if it seems like using the mysqli extension is overly complicated and inconsistent, especially when dealing with prepared queries, it is. this would be a good time to stitch to the much simpler and more modern PDO extension. while there should be a user matching the logged in user id, if there isn't, all the code dependent on there being a user should not be executed. a true value returned by mysqli_query() only indicates that the query executed without error. it doesn't mean that the query matched a row of data. you should instead test that the fetch statement returned a true value. also, all the rest of the code is dependent on there being fetched data. if there isn't, none of the remaining code should be executed. when mapping an input value to an output value, don't write out conditional logic for every value. use a 'mapping' array instead. there are a number of html markup errors. you should validate the resulting html at validator.w3.org don't repeat yourself (DRY) don't repeat conditional tests, just put everything in one conditional test. multiple spaces in html markup render as a single space. if you do have a need for multiple spaces, you would use a instead of escaping double-quotes in the php produced markup, use single-quotes. as to the performance problem, you need to profile the execution of the code, i.e. measure the time it takes for different sections of code to execute. i would start by timing the execution of the code from the start up to the QR code, the QR code, the generation of the html markup, and each of the main dompdf statements. once you know where the greatest amount of time is being taken, you can concentrate on finding and fixing the performance problems in that section of code.
-
you would need to post an sql dump with some sample data and the logo file to get specific help. a likely performance problem is using .png for the QR image and putting that image in several places in the document. if you convert it to a jpeg image, it should render more quickly as the jpeg format is natively supported by dompdf. to produce a jpeg for the QR image, see this link - https://phpqrcode.sourceforge.net/examples/index.php?example=711
-
if both arms_name_long and arms_name_short must be unique, you would want to detect which one or both are duplicates and display a separate and specific message in the appropriate span tag(s). as to how to do this, your database design must enforce uniqueness. both of those database table columns should be defined as unique indexes. you would then just attempt to insert the row of data and in the exception error handling, detect if a duplicate index error number (1062) occurred. It is at this point where you would build and execute a SELECT query to find which of the values are duplicates. here's a laundry list of things you should/should not be doing in this code - the for='...' attribute in the <label ...> tag must match the corresponding form field's id='...' attribute OR if you put the closing </label> tag after the form field, you can leave out the for='...' attribute entirely and if not used for anything else, leave out the id='...' attribute. for problems like item #1, you need to validate your resulting web pages at validator.w3.org any value you output in a html context needs to have htmlentities() applied to it to help prevent cross site scripting. if you use the null coalescing operator (??), it will simplify things like the value='...' attribute logic - value='<?=htmlentities($_POST['arms_long_name']??'',ENT_QUOTES)?>' the ids you use in a database context should be generated via autoincrement primary index columns, not using php random numbers. if you did have some need to generate unique random numbers and store them in a database table, you would need to insure uniqueness by defining the column holding them as a unique index and perform a duplicate index error check as described above for the arms_name_long and arms_name_short values. you should keep the form data as a set in a php array variable, then operate on elements in this array variable throughout the rest of the code. you should trim all input data before validating it, mainly so that you can detect if values where all white-space characters. once you do item #6 on this list, you can trim all the data at once using a single php array function. you should apply any ucwords() and strtoupper() modification to values only when you output them. the value you output in the form field value='...' attribute should be the trimmed, validated value, not the raw field value. when you make the database connection, you need to - set the character set to match your database table's character set, set the emulated prepared query setting to false (you want to run real prepared queries whenever possible), and set the default fetch mode to assoc (so that you don't need to specify it in each fetch statement.) i'm assuming that the ALTER TABLE... query is temporarily in the code and will be removed? btw - the ->query() method call executes the query. you don't need an additional ->execute() call and i'm not sure what doing so in this case will accomplish. if you use simple ? prepared query place holders and simply supply an array of input values to the ->execute([...]) call, it will greatly reduced the amount of typing you have to do for each sql query. as already discussed, you would first attempt to insert the data, then in the exception error handling, detect if the query produced a duplicate index error number. if it did, you would then execute a SELECT query to find which column(s) contain the duplicate values. for any other error number, you would simply rethrow the exception and let php handle it. you should not output raw database statement errors on a live/public server, as this gives hackers useful information when they internationally do things that trigger errors. if you only catch and handle duplicate (and out of range) database query exceptions in your code, and let php catch and handle all other database exceptions, php will 'automatically' display/log the raw database statement errors the same as its error related settings are setup to do for php errors.
-
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.