-
Posts
5,450 -
Joined
-
Days Won
175
mac_gyver last won the day on November 20
mac_gyver had the most liked content!
About mac_gyver
Profile Information
-
Gender
Not Telling
Recent Profile Visitors
156,628 profile views
mac_gyver's Achievements
-
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>"; } }