-
Posts
5,457 -
Joined
-
Days Won
175
Everything posted by mac_gyver
-
MySql (with whatever variations in capitalization you like) is the database server type. mysqli and PDO are php's extensions that allow your php code to communicate with the database server. if you understand what your mysqli based code is doing, you should be able to convert the code. all it's doing is - building an sql query statement. which should be in a php variable, in order to separate the sql as much as possible from the php, and allow you to separate the common php code used or in this case change the database extension being used. there's no difference between the sql query statement for the mysqli or PDO extensions, when using positional ? prepared query place-holders. prepare the sql query. there's no difference in the php syntax for the the mysqli or PDO extensions, except that the connection variable must be (and is usually named) for the extension being used. bind input data/execute the prepared query. If you are using php8.1 or higher, the php syntax for the execute statement is exactly the same. you can then use msyqli's get_result() and fetch_all() methods to fetch all the data from the result set.
-
you are not seeing the new record until you add another one, because the overall code on your page is out of order. you are processing the post method form data after the point where you are querying for and displaying the data on the page. did you read my reply at the end of your previous thread? as to the data being repeated, when you examine the raw data in the database table are there duplicates?
-
the OP's 'working' database code is using the mysqli extension. the provided autosuggest example is using the PDO extension, along with a connection variable name, $pdo, hinting at what database extension it is using. i recommend that you convert your existing database specific code to use the much simpler and better designed PDO extension.
-
you would use a typeahead/autocomplete/autosuggest input field, using ajax to get a list of matching people, that the user can then click on one to select it.
-
Possible to have a single MySQL query for multiple items?
mac_gyver replied to wrybread's topic in PHP Coding Help
you should have a category table, with id and name columns. this would define the different categories of items. the item table would have id, category_id, name, description, and any other columns needed to define each item. to display the category menu you would query the category table to get the category data that you want in the order that you want it, then loop over the result of this query to produce the category menu. if someone clicks on one of the category menu links, the category id in the link would be used to query for and display the items matching that category. -
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.