Jump to content

mac_gyver

Staff Alumni
  • Posts

    5,356
  • Joined

  • Days Won

    173

Everything posted by mac_gyver

  1. ginerjm's reply wasn't about a static form with x predefined sets of input fields. it was about entering one line item of data at a time, submitting the data (where it would be validated, so you can correct any errors as they occur), and then presenting an empty set of input fields for the next data item. the already entered data items would be shown with edit/delete buttons. to do just the entry of data, you don't need any javascript. you may however want to use javascript to do auto-suggest item selection. you should not expect the user to be typing in a large amount of item information. your user interface should allow selecting from existing items to help prevent data entry errors. your code layout would be - post method form processing, for Create(insert), Update, and Delete operations. you would trim and validate input data, storing validation errors in an array. if there are no validation errors, use the submitted data in an appropriate sql query. retrieve any existing order item data and display with edit/delete buttons for each item. if there are validation errors, display the form (which has only one set of input fields), re-populating the field values from the submitted form data. the user would correct any errors and re-submit the form. if there are no validation errors, display the form with empty field values. the user would enter the next set of data values and submit the form.
  2. writing code that works correctly requires that you have first defined what the code is going to do, so that you don't waste time writing/trying code that has nothing to do with the goal you are trying to achieve. a search page with pagination involves - 1) a search term input, from a $_GET parameter in the url. you only need a single input for this. it will either be set or it won't. you need to decide what to do when it is not set. will you output a message that the search term is empty and skip running all the database code or do you instead match all data, i.e. have no WHERE term in the sql queries? you should trim() this value before testing it to remove accidental white-space characters and to let you detect if an all white-space value was submitted. 2) a page input, from a $_GET parameter in the url. if this is not set, you would use a default value of 1. you would also limit this value between 1 and the total number of pages. a negative or a zero value are not valid and a page greater than the total number of pages won't match any data. 3) a COUNT(*) query to get the total number of matching rows. the result from this query is used to calculate the total number of pages. this is used to test/limit the requested page number and when producing the pagination links. 4) a data retrieval query to get the logical page of data. both the COUNT(*) query and the data retrieval query must have the same table(s) and any JOIN, WHERE, GROUP BY, and HAVING terms. you should build this common part of the sql queries in a php variable, then use that variable in both of the actual queries. the data retrieval query also has ORDER BY and LIMIT terms. if you retrieve all the data from the data retrieval query into a php variable, it will separate the database specific code from your presentation code, making it easier to test your code or to change the database extension without having to make changes though out your code. 5) code to display the retrieved data. 6) pagination links. the pagination links need to include any existing search term and the page numbers. the easiest way of doing this is to get a copy of any existing $_GET parameters and use http_build_query() to produce the query string part of the urls. some suggestions for your code - 1) the ....escape_string() functions can still allow sql injection if the character set that php is using isn't the same as your database table(s) and it is rare that anyone sets the character set when they make a database connection. you should use prepared queries when supplying external/unknown values to the sql query statement. a prepared query results in the simplest sql query syntax and the least amount of php code, provided that you use the php PDO database extension. 2) you should have error handling for all the database statements (connection, query, prepare, and execute.) the easiest way of doing this is to use exceptions and in most cases let php catch the exception where it will use its error related settings to control what happens with the actual error information (short-answer database errors will get displayed/logged the same as php errors.) 3) the search form should be on the same page with the search results and you should make the form 'sticky' by re-populating the field value with any existing search term. this will result in the least amount of code and allow the user to see what the existing search term is and to easily modify it if need be.
  3. you also have a "cannot see the forest for the trees" problem with a lot of unnecessary variables, statements, and conditional tests (boolean-like values can only be true or false, so comparing a value first with a true and then later a false is redundant clutter.) by putting the form and the form processing code on separate pages, you are doubling the amount of logic you need. also, if you switch to the much simpler php PDO extension and use exceptions to handle database statement errors (and in most cases let php catch and handle any database errors) a lot of the database related code will go away.
  4. do not pass the price through the form. you should get a minimum of data from the form, because all form data must be validated before using it. if all you are submitting is the item id and the quantity, you only have two pieces of form data that you must validate. the work-flow should be - 1) user selects an item, modifies the quantity (the initial quantity field value should be 1), and submits the form. 2) the server side processing code detects that a post method form has been submitted, validates the input data, and adds the item id (as the array index) and quantity to a cart session array variable. 3) to display the cart, get the item id's (see array_keys()), query the database to get all the item ids, names, descriptions, and prices for the items in the cart. loop over the retrieved data to display the cart, getting the corresponding quantity from the cart session array variable using the item id, performing any total calculation and display as needed.
  5. if the point of retrieving the price is to calculate the total before you add the item to the cart, there's no real need to do this, assuming that after each item is added to the cart you are displaying the contents of cart. you would retrieve the item name, description, price, and would calculate the total when displaying the contents of the cart. You can just display the price next to the item name in the option list if the sales rep needs access to the unit price.
  6. IMO using a select/option menu to pick a product to add to a cart is not a good user interface. there's a limited amount of information that can be displayed about each product, so picking between similar products will be difficult and once you get to 20-30 items no one is going to want to use a select menu. you should list out each matching (using a category/name selection/search) product with the name, description, price, thumbnail image, quantity field, and an add button. if you do have a use for a select/option menu to pick something, you would attach an onchange event handler to the select element, the option value should be the item id not the item name, the javascript would get the value of the selected option choice, use ajax to retrieve the data matching the selected item id, then populate any elements on the web page with the retrieved data. these are all very common tasks that you can research on the web to find example of. while you can display the price and calculate and display the total from the entered/selected quantity and the price, the only values that should be used on the server from the submitted data are the item id and the quantity.
  7. your php installation needs to be set up to log all php errors. there should be information in the web server error log file to help identify the problem.
  8. you have been given working logic (here and phpbuilder, which i just verified that both work) to test the amount, wallet, and wallet2/balance/earnings (you keep changing what it is called) and to calculate new wallet and wallet2/balance/earnings amounts, yet the code you continue to 'try' is using neither method. are you even reading the replies you are getting? next, in the code i reviewed and added comments to here, there's no logic to get the starting wallet2/balance/earnings value. wouldn't that be a necessary step to get the code to work? btw - your existing code has an UPDATE query at the correct point within the transaction/rollback logic. you would want to use the new wallet and wallet2/balance/earnings amounts in that existing single query, per the comment i added at that point, rather than to start adding more queries before the start of where the transaction/rollback logic starts.
  9. no. the u_paid_videos table holds the information about the items(videos) in the order, but it contains redundant data. it has nothing to do with the accounts table i mentioned. everything i stated has to do with database normalization (you can research what that means) and is about properly organizing the data, so that you are only storing the data you need and are not repeating values in multiple places. you are keeping track of two different type of things, 1) information about items/videos that are being purchased (as already stated needs an orders and an order_items table), and 2) user's money/credits. the orders table should have at a minimum, columns for - an id (auto-increment, produces an order_id), user_id (who placed the order), date_time (when the order was placed), and a status column (indicates what state the order is in.) i'm not sure what the session key is, but if it needs to be stored per order it would go in the orders table. the order_items table should have at a minimum, columns for - an id (auto-increment), order_id (what order the item is part of), item_id (the id of the item/video), quantity (this code is just a cart script and in general should support any quantity of an item), purchase_price (the price at the time of purchase), and a status column (indicates the status for each item in the order.) the account table should have at a minimum, columns for - an id (auto-increment), user_id (who the account belongs to), amount (the + or -- amount), transaction_type (wallet, balance), and date_time (when the transaction was made.)
  10. this code contains no useful comments, making it difficult to determine what it is trying to do, which makes it impossible to make changes to it. the original author, and you as you are making changes to it, should put useful comments in the code that describe what it is doing and why. this is what i think it is trying to do - <?php if(true) // whatever the actual conditional logic is { // get cost video // get the default video price, to use if there is no per video play price $db->where('name', 'video_play_price'); $db_cost = $db->getOne('config'); $video_cost = (float)$db_cost->value; // the number of submitted videos - used to determine if all records were inserted $count_video = count($id_array); $user_id = $user->id; // copy the user id for some reason // values shouldn't have thousands separators stored with them. formatting a number should only be done when it is displayed $wallet = (float)str_replace(',', '', $user->wallet); // add up the video prices $amout = 0; foreach ($id_array as $id) { // assuming this pt_secure function is actual secure, any $id in the following code should use $video_id instead $video_id = (int)PT_Secure($id); // get video data $video = $db->where('id', $id)->getOne(T_VIDEOS); // add the video play price if any, or the default price $amout += $video->video_play_price?$video->video_play_price:$video_cost; } // determine if the user has enough credits // it is here that you would include the balance amount if ($wallet >= $amout) { // you would calculate new wallet and balance amounts $wallet = (string)($wallet - $amout); // insert/update all the following queries as a group $db->startTransaction(); $inserted_records = 0; foreach ($id_array as $id) { // again, all the rest of the code should use $video_id, not $id $video_id = (int)PT_Secure($id); // get video data $video = $db->where('id', $id)->getOne(T_VIDEOS); // use the video play price if any, or the default price $video_cost_new = $video->video_play_price?$video->video_play_price:$video_cost; // add data to paid table $insert_buy = $db->insert('u_paid_videos', [ 'id_user' => $user_id, 'id_video' => $video_id, 'session_key' => $_SESSION['session_key'], 'video_play_price' => (string)$video_cost, // the cost at the time of purchase // this is the default video cost not the $video_cost_new 'video_title' => $video->title, // storing the title is redundant since you can retrieve it from the source video information 'user_id_uploaded' => $video->user_id, // the user who uploaded the video. this is also redundant // this should include the datetime of the purchase - actually there should be a purchase/order table and a purchase/order_items table ]); // count successful inserted records if ($insert_buy) { $inserted_records++; } //update the 'balance' of the user who uploaded the video // get the user's record $userwallet = $db->where('id', $video->user_id)->getOne(T_USERS); // credit the user 50% of the video cost $uploader_amount = $video_cost_new *0.50; // add to the balance $videouserwallet = $userwallet->balance+$uploader_amount; // update the record $db->where('id', $video->user_id); $update_balance = $db->update(T_USERS, [ 'balance' => number_format($videouserwallet, 1, '.', ''), // this is formatting with one decimal point only ]); } // update the current user's wallet (and balance) amounts $db->where('id', $user_id); $update_wallet = $db->update(T_USERS, [ 'wallet' => $wallet, // you would include the new 'balance' too ]); // if all the video records were inserted and the current user's wallet was updated, commit the changes if (($inserted_records == $count_video) && $update_wallet) { $db->commit(); echo json_encode([ 'status' => 200 ]); exit(); } else { $db->rollback(); echo json_encode([ 'status' => 400, 'error' => 'Buy process error' ]); exit(); } } else { echo json_encode([ 'status' => 400, 'error_num' => 1, 'error' => 'Not enough money' ]); exit(); } } else { echo json_encode([ 'status' => 400, 'error' => 'Bad Request, Invalid or missing parameter' ]); exit(); } if i have incorrectly deduced what any of these things are doing, make corrections to the comments before proceeding. if this code had useful comments, so that the meaning of the line of code producing the $video_cost_new value would be in recent memory, there probably wouldn't be a mistake in the pricing value used in the insert query. the following line should use $video_cost_new - 'video_play_price' => (string)$video_cost, // the cost at the time of purchase // this is the default video cost not the $video_cost_new next, the data design has one serious flaw and one that should be corrected - 1) the wallet and balance amounts should NOT be just columns in the user's row that get updated to change the value. by having just a value, you don't have any 'audit trail' should a programming mistake, duplicate form submission, or nefarious access alter a value incorrectly. you should instead have a separate 'account' table that gets a new row inserted for each transaction that affects the amount. this table would have all the who, what, when, where, and why information about each transaction ('wallet' or 'balance' would just be transaction types.) to get the total at any point in time for a user, you would just SUM() the +/- amounts for any particular user id. to get the either or both of the current 'wallet' or 'balance' amounts, you would group by the transaction type for any particular user id. 2) you should actually have two tables to hold the video purchase information. the first table should hold the unique/one-time information about the purchase. this will assign a purchase order id. the second table would hold the unique/one-time information about the items that were purchased, related back to the first table through the order_id. lastly, i put comments in the code where it would need to be modified to do what you are asking. two are near the if ($wallet >= $amout) { conditional test (LOL amount is misspelled in the code.) the last one is in the update query (which should instead be one or two insert queries for the account table) for the current user's wallet (and balance) amounts.
  11. you are likely getting that same error when the the login works, but it is probably being hidden by a redirect. since you only use mysqli_stmt_free_result() if you are using mysqli_stmt_store_result(), which you aren't in the posted code, doesn't that mean that you shouldn't be using mysqli_stmt_free_result() at all? you need to switch to the much simpler PDO extension and use exceptions to handled db statement errors. it only takes 4 lines of code to replace the 11 lines you have from the sql query statement through to the fetch statement. $query = "SELECT id,recruits_number,sponsor_username,account_activation_status,id_video_verification_status,id_verification_video_file_url,username,password,primary_domain,primary_website_email,registering_country,registering_ip,registering_browser,registering_os,registering_isp,age_range FROM users WHERE $querying_column = ?"; $stmt = $pdo->prepare($query); $stmt->execute([$login_username_or_email_or_domain]); if(!$row = $stmt->fetch()) { // the email/username was not found // set up the failed login message } else { // the email/username was found, check the activation status and then verify the password hash to finish logging in // the fetched data is in the associative array $row }
  12. the biggest issues with your code (some of which have already been mentioned) are - 1) all the form processing code isn't inside the conditional statement detecting if a form has been submitted, so the part where the sql query is at can be executed when there is no post data to use. all the form processing code needs to be inside the conditional statement and if this is the only form processing code, you should instead detect if $_SERVER['REQUEST_METHOD'] == 'POST' 2) sqlsrv_errors() returns an array. you cannot echo an array. to dump the errors for debugging purposes, either use var_dump() or print_r(). also, your code needs only execute the rest of the database code if $getResults is a true value. the rest of the errors are 'follow on' errors because the query failed. you should also have some error handling for the database connection so that you only execute the query if the connection worked. 3) after you have detected that the form has been submitted, you must validate all input data before using it. this is doubly important if the form data specifies column/table names for an sql query statement, since no amount of escaping of the values (it's not string data and it's not being used in a string context) or using a prepared query (you can only supply data values, not column/table names via prepared query place-holders) will protect against sql injection. for column/table names, you must either validate that each value is only and exactly a permitted column or table name or you must use some sort of id mapping, where you submit id values instead that get mapped to column/table names internally in the code so that only id values that have a valid mapping can be used.
  13. to do this, you will need to dynamically build the sql query statement, with a place-holder for each value (you can use a few array function calls to do this), then you will need to dynamically bind all the parameters. unfortunately, the php mysqli extension was designed poorly concerning prepared queries and dynamically calling the bind_param() statement requires a lot of extra, slow, messy code. if you can, switch to use the php PDO extension. it is much easier, straightforward, and consistent to use, over the php mysqli extension. to do this using the php PDO extension, after you build the sql query with the correct place-holders in it, you don't need to call any bind statements, and can just supply the exploded array as the input parameter to the execute() call.
  14. seems like this has been asked and answered before - https://forums.phpfreaks.com/topic/302345-how-to-loop-the-following-question-and-answer/
  15. calculate how long it will take for your table to have 5 million rows in it. with today's server hardware, 5 million rows in a properly indexed table is about the point where you need to start worrying about doing things like using partitioning or archiving older data.
  16. some separate issues - 1) a person's age is not a fixed value, unless they are dead. for people that are still alive, their age changes each year (or every 4 years if born on Feb. 29). you should instead be storing a date of birth and then calculating the age when needed. 2) you should be using php's password_hash() (and password_verify()) functions for your password hash.
  17. the fatal error is occurring after the point where the sql query statement is being executed (unless the profile related query is after the code you have posted), so it is not directly the cause of the data not being inserted, but it is a separate issue that MUST be fixed. if the data isn't being inserted into the reports table (is that the correct table for the profile information?) then the db_qry() function isn't detecting if there is an error and returning a false value so that the or die(...) logic has something to operate on. you would need to post the code for the db_qry() function for us to be able to directly help. as to the fatal error, if you read the php.net documentation for that function, you will find what it means and what to do to fix it. however, the code already has the 'fix' in it. you use the $_SESSION variable directly in assignments and references, combined with a session_start(); statement near the top of the code on any page that sets or references a $_SESSION variable. lastly, your code has some even more serious problems than what you are trying to currently fix. the reason for the first and third errors are because your php version was updated to at least php 5.5. if your php version gets updated again, to php 7, ALL the database code using the php mysql_ statements will stop working because the php mysql_ extension has been removed from php and your code will need to be rewritten. your code is also most likely open to sql injection, since it is putting data values directly into the sql query statement. switching to the php PDO extension and using prepared queries would be the best why of solving both of these problems.
  18. your pagination should retrieve the total number of rows you want to display on the page and it should use a variable (or defined constant) to specify the number of rows so that you don't have a hard-coded value in three different places in the code (and if you apply a little algebra to your equation, you only need to use the value in two different places.) next, as you are looping over the data to display it, you would either have a loop counter and a conditional test to check the value in the counter or you can use array_chunk() to break up the result set into chunks of the size you want. if you only want to display an advert once, you would test the absolute value of the counter. if you want to display an advert every n number of blog posts, you would use the Modulus operator to test the value of the counter. you would also test if the number of rows in a result set is less then the point where you want to display the advert, for example the last page of results, then display it once on the end of the output. lastly, the php mysql_ extension is obsolete and has been removed from php. you need to convert your code to use the php PDO extension, and use prepared queries to supply data values to your sql query statement.
  19. do you have php's error_reporting set to E_ALL and display_errors set to ON (preferably in the php.ini) on your development system, so that php will help you by reporting and displaying all the errors it detects? do you have any error handling for the mysqli statements, so that you will know if and why they are failing? if you enable exceptions for the mysqli extension (there are examples in the php.net documentation showing how to do this), combined with the above two php settings, will cause any mysqli errors to throw an exception that php will catch and then display the actual error information. the above two items will get your code to tell you when and why it is failing. next, there are some problems and security issues with the code - 1) you cannot successfully use the ip address to identify a visitor. several people can share the same ip address and the ip address can change during one visit to a site (a cable/dsl modem gets reset for example.) you need to generate a cart id, store it in a session variable, and use it in the cart data. the easiest way of generating a cart id is to have an 'orders' table and insert a row into the table, with a status value that indicates a 'pending' order, i.e. a cart, and then get the last insert id and use this as the cart id. 2) you should not put data values directly into sql query statements. you should use prepared queries, with place-holders in the sql query statement, then supply the data values when you execute the query. the mysqli and PDO extensions both support prepared queries, but the PDO extension is much easier to use. if you can, you should switch all your code to use the PDO extension. 3) function names should indicate what the function does. a function named cart() could display the cart, add an item to the cart, update item(s) in the cart, or delete item(s) from the cart. the name should give a hint to anyone reading the code what the function does. 4) variable names and database columns names should also be descriptive. 5) any inputs a function needs should be passed as call time parameters. 6) you should use a post method form when you cause an action on the server, such as creating, updating, or deleting data. your add to cart should use $_POST, not $_GET. 7) you should validate data before using it. what happens if the 'add_cart' value is set but it's empty? it's not a number? it's not a valid product id? your cart needs a quantity column, so that someone can select more than one of something. 9) you need to define what your code is going to do for each possible combination of inputs and existing data. what should your code do if an item is already in the cart? should it output a message, replace the existing quantity with a one, or add one to the existing quantity? 10) your database table holding the cart contents should have the cart id and product/item id defined as a composite unique index so that you can only insert any item once in a cart. doing this will also allow you to use an INSERT ... ON DUPLICATE KEY UPDATE ... query to manage inserting a new item or updating the quantity of an existing item using a single sql query.
  20. a data driven method that doesn't involve program logic for each choice - // define the choices in a data structure $choices = array(); $choices['airflow'] = 'Beds with Airflow Fibre Mattresses'; $choices['supreme'] = 'Supreme Collection'; // add more entries here... $base_url = '/folding-beds/browse-by/'; $selector = isset($_GET['selector']) && isset($choices[$_GET['selector']]) ? $_GET['selector'] : 'airflow'; // get the selector or default to 'airflow' $href = $base_url . $selector; $text = $choices[$selector];
  21. $row['entry_name'] == $name; ^^^ this is a comparison, not an assignment, so one would expect nothing to be altered.
  22. this browser behavior cannot be changed. it occurs anytime the 'last' action for a url was a post method form submission. the way to prevent this is to do a header() redirect, i.e. a get request, to the exact same url after you have finished processing the post method form. see this link - https://en.wikipedia.org/wiki/Post/Redirect/Get
  23. also, at about line 10 in the friend requests code, you have this - if ($numrows < 1) { $numrows is an array, which may be empty if the query didn't match any rows, and that comparison makes no sense. use variable names that indicate the meaning of the data. this is the new friend request query result/data/rows and the variable name should be some variation of that information - $friend_request_rows would be one possible choice. then, an empty array is treated as a Boolean false, so you can directly test it in an if() conditional or you could use count() to find how many rows are in the array. next, your friend_one and friend_two columns should be the user id, not the user name. by storing the user name, you cannot edit any user name without going through and updating all the records holding the user name. storing the user id will also result in the least amount of data storage requirements and produce the fastest queries. finally, don't run queries inside of loops. your query to get the user table information (avatar) should instead be gotten by change the new friend request query to be a JOIN query with the user table. this will also 'fix' the problem in the current code with the $i variable that only 'works' if there is a single new friend request.
  24. your php code isn't outputting anything. you are producing the $data array, but you are not json encoding it and echoing it to the browser. the friend requests code is also echoing a string value and then exiting. this may be just for testing, but because the output isn't in the format that the ajax code expects, the javascript isn't going to do anything. you need to get to the point of being able to write, test, and debug your code. for the time being, forget about using ajax. just write a html form that submits the expected fields and values to your php code and get your php code to work. once it produces the expected output for all cases of inputs, then you are at the point where you can add ajax.
  25. start by setting error_reporting to E_ALL. by setting it to a 1, the only errors that are being reported are fatal runtime errors.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.