-
Posts
5,452 -
Joined
-
Days Won
175
Everything posted by mac_gyver
-
I'm gusseting the posted picture is after you have submitted the form? after you set php's error_reporting to E_ALL and display_errors to ON, you should find the reason for that problem. here are a ton of coding practices that will help organize and simplify the code - 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 some specific points for the posted code - use 'require' for things your code must have. include/require are not functions. the () around the path/filename don't do anything and should be left out. don't echo large amounts of static html. drop out of php mode and put the html inline. if you use php's short open-echo tag and a closing tag around a value, you can output variables in the html document using <?=$var?> don't escape double-quotes inside a php double-quoted string. simply use single-quotes inside the string. don't unnecessarily switch out of and back into php mode. just stay in php mode. don't use post method forms for navigation. use href/links. your markup is out of date. you need to validate the resulting web pages at validator.w3.org because this entire page requires the current user to be an administrator, preform the user level test once, near the top of the code and take an appropriate action if the user isn't an administrator. to get a form to submit to the same page it is on, simply leave out the entire action='...' attribute. you need to store the customer first and last names in separate columns. as a more advanced programming subject, if you have more than 2-3 form fields, you need to dynamically validate and process the form data and dynamically produce the form fields, instead of writing out code for every possible field. some points for the post method form processing code - don't attempt to detect if the submit button is set. there are cases where it won't be. instead, detect if a post method form was submitted. keep the form data as a set in a php array variable, such as $post or $data, then operate on elements in this array variable throughout the rest of the code. trim all the input data before validating it, mainly so that you can detect if all white-space characters were entered. once you do item #2 on this list, you can trim all the data using one line of code. validate all the now trimmed input data, storing user/validation errors in an array using the field name as the array index. after the end of the validation logic, if there are no errors, use the submitted form data. use a prepared query to prevent any sql special characters in value from being able to break the sql query syntax. if it seems like using the mysqli extension is overly complicated and inconsistent, it is. this would be a good time to switch to the much simpler and better designed PDO extension. if an insert/update query can produce duplicate data errors, you need to test for and handle this in the query exception handling for the query and setup a message for the user (add it to the array holding the user/validation errors) letting them know what was wrong with the data that they submitted. after using the submitted form data, 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. this will prevent to browser from trying to resubmit the form data should that page get browsed back to or reloaded. to display a one-time success message, store it or a flag value in a session variable, then test for this session variable, display the message, and clear the session variable at the appropriate location in the html document. if there are errors, the code will continue on to redisplay the html document, where you will test for an display any errors, either all at once or individually adjacent to the field they correspond with, and populate the form fields with any existing data so that the user doesn't need to keep reentering values 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.
-
you would ORDER BY the id (autoincrement primary index) column instead. a DELETE query has the same ORDER BY and LIMIT terms as a SELECT query.
-
The closing </option> tag on the $ThisYear output is missing the closing >, so the following markup is broken. check the 'view source' of the output in your browser.
-
do you have php's error_reporting and display_errors set so that php will help you by reporting and displaying all the errors it detects? error_reporting should always be set to E_ALL. on a live server, you can temporarily set display_errors to ON to get immediate feedback as to any problems. these settings should be in the php.ini on your system, but can temporarily be put in your php code, right after the first opening <?php tag. if php's output_buffering setting is on (another bad decision by php), you can have output before a header() statement and the header() will work. you should check using a phpinfo() statement to see what this setting is, as it also hides non-fatal php errors and any debugging output from your code. a full URL is not a problem. however, if the protocol changed, e.g. from https to http, the session won't match, because session cookies are kept per protocol. you are doing this on live web hosting? have you set your session_save_path to be to a location within your hosting directory tree, outside of/below the htdocs folder, so that all the session garbage collection by all the other hosting accounts isn't deleting your session data files? if your session data files are in the default tmp folder with all the other accounts, the shortest session.gc_maxlifetime of all those accounts is what will affect your session data files. the only user data you should store in a session variable upon login is the user id (autoincrement primary index.) you should query on each page request to get any other user data, such as a username, permissions, ... this is so that any changes made to this other user data will take effect on the very next page request after they have been changed. do you really want a situation where you have demoted or banned a user and they can continue to visit your web site because their session data says they can? and is this inside of code testing if a post method form has requested the page, so that it won't get executed just because a browser/client has made a get request to the page? browser's are now doing things like pre-requesting pages that are in your browser's search history when you start typing things in the address bar. also, a session can hold data other then who the logged in user is. you should only unset those session variable(s) that are specific to the logged in user. the code you have shown has the form processing code and the form on separate pages, with a bunch of extra redirects. this results in nearly 2x the amount of code, provides a bad User eXperience (UX), and depending on how you are getting data/messages back to the form, is open to phishing attacks and cross site scripting. the only redirects you should have in your application code are upon successful completion of post method form process and they should be to the exact same URL of the current page to cause a get request for that page. this will prevent the browser from trying to resubmit the form data should that page get browsed back to or reloaded, where someone can use the browser's developer tools to see what the form data, such as the password, is. the code for any form and related form processing should be on the same page. 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
-
foreach() function to replace each() function in while loop
mac_gyver replied to us66mo's topic in PHP Coding Help
the code's looping until there's an error (while no error). just use a foreach loop, with a break when the error occurs OR perhaps loop over all the data, producing an array of errors, then use the array of errors after the end of the loop? what does a sample of the data look like, what exactly are you doing with it, what do you want to do upon the first error or do you want to check every entry for errors? -
the code that's responsible for populating the $user variable needs to setup a default value if there is no user. the code testing the value then only needs to be concerned with what the value is. also, at that point, you are only dealing with a true or false boolean value. you should test for the true case, e.g. if($user){ // there is a user} else { // there is not a user}
-
two problems - 1) you don't have php's error_reporting set to E_ALL (it should always be this value) and display_errors set to ON, preferably in the php.ini on your system, so that php will help you by reporting and displaying all the errors it detects, and 2) once you do that, you will get a php error about the 1st argument being a string instead of a datetime (Interface/immutable) object. to use date_format() you must first create a datetime object from the fetched value - $DD = new datetime($row["OrderDate"]); echo $FormattedDate = date_format($DD,'d-m-Y H:i');
-
one primary reason has already been given - any format where the fields are not from left to right in most significant to least significant order cannot be directly compared by magnitude. additional reasons for using a standard sgl data type for storing dates/datetimes are - it allows you to sort using the values (because date comparisons directly work on the values) it allows you to use all the built in sql date/time functions this standard format is also what php's date/datetime functions accept and use by default is uses the least amount of storage it results in the fastest queries you store and operate on dates/datetimes internally using this standard format. you only format values in your local format when you display them. if you have a lot of existing data stored in some other format, you can add a standard date or datetime data type column to your table, and use MySql's STR_TO_DATE(str,format) function in an UPDATE query to populate the new column from the existing values. once you have converted and tested your code to use the new column values, you can delete the old column from the table.
-
you need to use a DATETIME data type and store the values in a sql YYYY-MM-DD hh:mm:ss format (the equivalent php date() format specifier would be 'Y-m-d H:i:s') this will allow you to preform date comparisons directly on the values in the sql query statement. you would then use a WHERE clause in a query - WHERE your_datetime_column >= NOW() - INTERVAL 1 day to match records that are within one day of the current date. edit: supplying a a value that 'looks' like the list of parameters to a function call doesn't work. this is treating the whole value as the 1st parameter (hour) or is possibly producing a php error.
-
learning involves forming a theory about how something works, performing an experiment to prove or disprove the theory, observing the result of the experiment and concluding if the theory was correct or not. you will learn much better and quicker if you make an attempt at designing, writing, and testing code to see if it does what you expect. if(loggedin()) { // code for all logged in users if($user_level == 1) { // code for a logged in user with level == 1 } else { // code for a logged in user with level != 1 } } else { // code for a non-logged in user } i recommend two things - 1) use defined constants, such as define('ADMIN_USER',1);, instead of literal numbers, so that anyone reading the code can tell what the numerical values mean, 2) when conditional 'failure' code is shorter then the 'success' code, invert/complement the condition being tested and put the shorter code first. this will make your code easier to read and understand.
-
that your current code is open to sql injection (i could inject sql that will add a UNION query to your SELECT query to output the entire contents of your user(s) database table) means that you must go through the database specific code and secure it. using the much simpler and better designed PDO extension results in the least amount of work to accomplish this. here's how you can convert any sql query that has php variables being put directly into it into a prepared query, using the PDO extension - remove, and keep for later, any php variables that are inside the sql query statement. note: any wild-card characters in a LIKE comparison are supplied as part of the data value not as part of the sql query statement. remove any quotes or {} that were around the php variable and any concatenation dots/extra quotes that were used to get the php variable into the sql query statement. put a simple ? prepared query place-holder into the sql query statement for each value. call the PDO prepare() method for the sql query statement. this returns a PDOStatement object. call the PDOStatement execute([...]) method with an array of the variables you removed in step #1. for a query that returns a result set, fetch the data from the query. see the PDOStatement fetch() method when fetching a single row of data. the PDOStatement fetchAll() method when fetching all the rows of data at once. and occasionally the PDOStatement fetchColum() method when fetching a single column from a single row of data. forget about any num rows function/method/property. just fetch then test if/how many rows of data there are. for a query that doesn't return a result set, you can use the PDO lastInsertId() method and the PDOStatement rowCount() method with an insert/update/delete query to get the last insert id and the number of affected rows. if you build the sql query statement in a php variable, it makes debugging easier since you can echo the sql query statement to see what it is. this also helps reduce mistakes since it separates the sql query syntax, as much as possible, from the php syntax. the sql query syntax for a PDO and mysqli prepared query is identical. the difference is in the php code needed to prepare, bind input parameters, execute the query, and fetch the data. mysqli has added a couple of methods in later versions of php that tries to make it more like the PDO extension, but these methods have a limitation in that they treat all data values as strings, so they are not useable for values that must be numerical (a limit clause) or are boolean or null values.
-
here's an example showing how to dynamically build the WHERE clause, as a prepared query, using the PDO extension - $where_terms = []; $params = []; // conditionally add the lorry term if($lorry != 'all') // note: your html and your default value for this input is using 'all' and this comparison must match that value { $where_terms[] = 'lorry = ?'; $params[] = $lorry; } // add the date_created term $where_terms[] = 'date_created BETWEEN ? and ?'; $params[] = $date_start; $params[] = $date_end; $where = implode(' AND ',$where_terms); // build the (existing) query $sql = "SELECT * from `sales` $where order by date_created desc"; // prepare, execute, and fetch the data using the PDO extension $stmt = $pdo->prepare($sql); $stmt->execute($params); $sales_data = $stmt->fetchAll(); // at the point of producing the output, you can test if $sales_data is a boolean false value to output a message starting that there is no data to display (i would do this above the start of the html table) // if there is data, you can loop over $sales_data to produce the output
-
here's some points about the attached code, most of which will simplify what it is doing - if you put the closing </label> tag after the form field it corresponds to, you can leave out the for='...' and corresponding id='...' attributes. if you put your database connection code in an a separate .php file and and require it one time on a page, you won't need to worry about posting it or your connection credentials when you ask for programming help. any query that may match multiple rows of data (the lorries query) should have an ORDER BY ... term so that the rows will be in a specific order. your code is conditioning and setting default values for the 3 inputs. you should use these conditioned inputs throughout the rest of the code. the current code using $_GET['lorry'] is producing php errors (visible in the 'view source' of the page) the first time your page is requested. the $start_date and $end_date values are already strings in a "Y-m-d" format. Don't Repeat Yourself (DRY) and reformat them again when you use them. any dynamic value you output in a html context needs to have htmlentities() applied to it to help prevent cross site scripting. you should dynamically build the WHERE ... clause with only the terms that you want. if you put the terms into an array, with the lorry term being conditionally added when it is not equal to 'all', you can simply implode the contents of the array using the ' AND ' keyword to produce the WHERE clause. you must use a prepared query 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. if it seems like using the the mysqli extension with prepared queries is overly complicated, it is. this would be a good time to switch to the much simpler and better designed PDO extension. the date_created column should be a DATE data type. if it is, you don't need to use sql's date() or sql's unix_timestamp() on it or php's date(...strtotime(...)) on it to get yor code to work. if the sales query doesn't match any data, you should output a message stating so. don't run queries inside of loops. you should use one query to get all the data that you want. point #7 address how to leave the lorry term out of the WHERE clause when it is the 'all' value.
-
Fetching array of domains from external file
mac_gyver replied to Moorcam's topic in PHP Coding Help
the curl code is making a http(s) request to the URL, just like a browser would. because it is to a .php page, the php code is being executed on the target server and what you get back is whatever that page outputs. you do not get the raw php code. because you are trying to transfer data, i recommend that you use JSON and use echo json_encode($domains_content); in the domains.php code, then after you successfully receive that JSON string from the curl call, you can use json_decode() on it to get the array of data. -
$_SERVER['DOCUMENT_ROOT'] is a file system path. it is used when you reference a file through the file system on the server, such as when you require a file through php code or use a statement like file_get_contents(). these are not the same as URLs that a browser uses when it makes a request to a web server. you would need to post examples showing what you are trying to do to get more specific help.
-
you should only have one user/authentication database table. a staff member is a user with specific permissions/privileges (and you should query on each page request to get the user's current permissions.) what you currently have either duplicates user id's and/or has a extra code/queries in it. some other points, most of which simplifies what you are doing - because logoutUser() is a function, you WOULD use the $user_id input parameter in the code, like it was written. you apparently have two different functions, since the last code is using $userId as the input parameter. you should be using php8+, where the default setting is to use exceptions for database errors. when using exceptions, if the code continues past any statement that can throw an exception (connection, query, exec, prepare, and execute), you know that no error occurred and you don't need conditional logic to confirm so. you should never unconditionally output raw database errors onto a live web page, where it gives hackers useful feedback. when using exceptions, simply do nothing in your code for most errors and let php catch and handle the exception, where php will use its error related settings to control what happens with the actual error information (uncaught database exceptions will 'automatically' get displayed/logged by php.) a session can hold things other than the user's id. the logout code should only unset that specific session variable. the redirect you preform upon successful completion of post method form processing code MUST be to the exact same URL of the current page to cause a get request for that page. this will prevent the browser from trying to resubmit the form data should that page get browsed back to or reloaded. for a logout this doesn't matter, but for something like registration/login, if you browse back to the form's action page, you can use the browser's developer tools to look at the data that the browser resubmits and see what the username/password is. there's no need to close database connections in your code since php destroys all resources when you script ends. in fact the close statement you have shown is never reached since your current logic exits in all cases before ever reaching it. you cannot set display_startup_errors in your code because php has already started by the time your code runs.
- 10 replies
-
- 1
-
- php
- prepared statements
-
(and 2 more)
Tagged with:
-
you are trying to pattern match to convert one language/syntax to another. do you accept that from your students, or do you actually expect them to learn the meaning of the words and syntax you are trying to teach them? writing code is no different than a writing assignment in a foreign language. the pdo rowCount() method is not guaranteed to work with a SELECT query. as has already been written in your replies, simply fetch the data from a query into an appropriately named php variable, then test if there is any data in the variable. if there isn't, display an appropriate message. if there is, loop over the data to produce the output. here's a pattern for you to use - // the database specific code, that knows how to query for and fetch the data // a prepared query, with a place-holder where the dynamic value will be used $sql = "SELECT * FROM ember_students WHERE teacher = ?"; // prepare the query $stmt = $pdo->prepare($sql); // execute the query with an array of the dynamic value(s) you removed from the sql query statement $stmt->execute([$uname]); // fetch all the data from the query $result= $stmt->fetchAll(); // the presentation code, that knows how to produce the output from the data if(!$result) { echo "<p>There is no data to display.</p>"; } else { foreach($result AS $row) { // you can put php variables into a double-quoted php string. no need for error-prone extra quotes and concatenation dots print "{$row['lname']}, {$row['fname']}<br>"; } }
-
php update mysql database with form/checkbox
mac_gyver replied to tonypoli783's topic in PHP Coding Help
the current markup will only submit the last checkbox value that is checked. to submit a set of values, the form field name needs to be an array, e.g. name='team[]' you also need to apply htmlentities() to dynamic values being output in a html context so that any html entity in a value, such as a ', cannot break the markup. -
this is a symptom of the browser not recognizing quotes around a value attribute in the markup. you would need to post your code and a sample of your data that reproducers the problem for anyone here to be able to help. also, what does the 'view source' in the browser show for the markup? btw - instead of escaping double-quotes inside a php string, you can simply use single-quotes.
-
it's a matter of functionality/purpose, not preference. a non-prepared query is used when there are no dynamic values being supplied to the query. a prepared query is used when you are supplying dynamic values to the query, in order to separate the parsing of the sql query syntax, from the evaluation of the values during the execution of the query. this is so that values like didn't or O'tool, which contain an sql special character, cannot break the sql query syntax, which is how sql injection is accomplished. in one of your previous threads i gave detailed instructions on converting an sql query with php variables being put directly into it, into a prepared query.
-
PDO examples - a non-prepared query. assuming the literal 4 (which is not a string, it's a number) is hard-coded in the query - $query = "SELECT * FROM ember_features WHERE id = 4"; $stmt = $pdo->query($query); $row = $stmt->fetch(); a prepared query. assuming the value being shown in this query is a dynamic value - $query = "SELECT * FROM ember_features WHERE id = ?"; // a simple ? place-holder where the dynamic value is used at in the query $stmt = $pdo->prepare($query); // prepare the query $stmt->execute([ 4 ]); // execute the query, suppling dynamic value(s) as an array to the execute() call $row = $stmt->fetch(); where did you find this connection code? here's everything that's wrong with it - it's not setting the character set to match your database tables, so character conversion can occur, breaking multiple-byte characters it's not using exceptions for errors, which is the default setting now, which simplifies all the error handling it's not using true prepared queries. by using emulated prepared queries (the default) and not setting the character set, your queries are open to sql special characters in a value being able to break the sql query syntax, which is how sql injection is accomplished it's not setting the default fetch mode to assoc, so you will need to specify the fetch mode in each fetch statement there's no point in catching and handling a connection error in your application since a user to your site can do nothing about it and doesn't need to know it is the reason a page isn't working. catching and outputting the raw error information also helps hackers when they intentionally trigger connection errors (by flooding your site with requests that consume all the database connections.) if you have ever looked at a connection error, it lists the database server host/ip address, the database username, if the connection is using a password, and web server path information. do you really want to give someone this much information about your site? you should only catch and handle user recoverable database errors in your application, such as when inserting/updating duplicate user submitted data. for all other query errors and all other type of queries, simply do nothing in your code and let php catch hand handle database errors.
-
the problem is most likely going to be something preventing the session_start() from working, which php's error reporting and display/logging will tell you. so, setup php's error_reporting and display_errors/log_errors as suggested, and confirm that they actually got set to those values by using a phpinfo() statement in a .php script. doing this ^ opens your site up to a phishing attack, where someone can trick one of your users to enter their login credentials on the phishing site, then redirect them to your site and get your site to display a message to make it look like they just mistyped the values. don't redirect all over your site and don't put values on the end of the URL that determine what the user will see in the way of messages.
-
you are likely getting a php error that would help identify the problem. is php's error_reporting set to E_ALL (it should always be this value) and either temporarily set display_errors to ON so that the reported errors will get displayed, or set/make sure that log_errors is set to ON and check the php error log. also, either check what a phpinfo() statement shows on both systems for the output_buffering setting, since it can both affect how your code works and can hide non-fatal php errors and debugging statements you put into your code. next, your description of the coding has you writing an maintaining a bunch of extra code and redirecting around on your site. the code for any form processing/form should be on the same page. the only redirect you should have in your code should be upon successful completion of the post method form processing and it should be to the exact same URL of the current page to cause a get request for that page.
-
in the phpinfo output, there's a value near the top named - Loaded Configuration File. is this the same php.ini that you checked? next, search for the error_reporting and display_errors output. what are both the local and master values for these? here's 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 the default setting now 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 ]; $pdo = new pdo("mysql:host=$DB_HOST;dbname=$DB_NAME;charset=$DB_ENCODING",$DB_USER,$DB_PASS,$options); in your previous thread, i have instructions on converting a query, that has php variables being put directly into it, into a prepared query. also from that thread - if you want to post examples of your existing code, i/we can show what it would look like using current practices. a lot of the coding suggestions given in that thread actually eliminate code, so that you can just remove things, rather than spending time updating them.
-
it's your php code that accesses the database, not the students that use your web site. your students login via the php authentication script that runs on your web site. if you set the php error related settings to the values that i posted, instead of getting a http 500 error page, you will get the actual php errors, assuming that php is setup and works on the server. have you created a .php page with a phpinfo(); statement to confirm that php works at all? because the mysql_ extension has been removed, along with magic_quotes, that provided some protection against sql special characters being able to break the sql query syntax for string values, which is how sql injection is accomplished, ALL of the code dealing with data values being put directly into the sql query statements MUST be updated. if you are not interested or capable of doing this level of changes, you are going to need to hire someone. the PDO extension provides the simplest way of accomplishing these changes.