Jump to content


Staff Alumni
  • Content Count

  • Joined

  • Days Won


Everything posted by mac_gyver

  1. the 'echo'ed sql query statement has some single quotes around the 2nd occurrence of the time column. this 1st showed up in the OPs post. edit: which Barand just posted too without any notification from the form software about a new post in the thread.
  2. the above logic is a problem unto itself. password_verify() returns a boolean true/false value. the above logic will change operation depending on what $dbPassword starts with. remove the !=$dbPassword from that line.
  3. for the example you posted, they are not empty values. they consist of two double-quotes each. empty values would be - username=&password=. of concern would be why your ->authenticate() method call is returning a true value for a username equal to a string consisting of "" and a password equal to a string consisting of "" also, your use and test of $_GET['secureSubmit'] will be true as long as there's any non-empty/non-zero value in the url. the =true in the url is a string consisting of the letters - t,r,u, and e. only secureSubmit=&... and secureSubmit=0&... would fail the logic test.
  4. password_hash() is used when the hash of a password is saved, i.e. during registration/password changes, and the hash it produces for a given input is different each time since a random salt is generated and used each time it is called. password_verify() is used to test if a submitted password corresponds to a saved hash.
  5. the example you have shown implies you have sets of same meaning data stored in a single row in the database table. this is a bad design, resulting in more code/queries to manage the data. research database normalization to find out how to properly store data. each set of data should be stored in a separate row in the database table, with an auto increment id column. this will establish a unique identifier that you can use when dynamically building the edit links. the id from the link would be used in the edit.php code to retrieve the correct row of data to populate the form fields with. the id would be passed in a hidden field in the form. the process.php code would detect that a post method form has been submitted, enforce any user 'edit' or ownership permissions, validate the input data, then use the input data when executing the update query.
  6. wherever you read that, it (should have) included the information - 'when using emulated prepared queries and supplying the values via an array to the ->execute() method call'. since you are not using emulated prepared queries, you can use place-holders for the limit values.
  7. store them in a session array variable as stated in your previous thread. all what code? the submitted form data will be in $_POST. the only thing submitted when someone adds an item to the cart is the item id (sku) and the quantity (which could be an implied 1.) the form processing code needs to add new items to the session cart array variable with the submitted quantity or implied quantity of 1 or add the submitted quantity to the existing quantity if the item is already in the cart. you can have code to handle other operations, such as removing an item from the cart, clearing the entire cart, or updating the entire cart. if there's a lot of code/variables to do this, somethings wrong with the existing code. the server-side code to perform the 'add' to cart operation is probably about 20 lines of code. anything occurring in the client-side javascript are for display purposes and don't affect what's in the server-side cart. when you process the contents of the server-side cart (item ids and quantities), you calculate any amounts on the server (accepting prices/amounts from the client-side code allows someone to purchase things for the price they want, not the price you have set.) if you want specific help with any existing code you will need to post it.
  8. yes to storing the data in a session variable, no to just concatenating it to a single element. the 'cart' session variable needs to be an array, with the array index being the item id and the value stored in the array being the quantity. this will result in the simplest code when referencing or manipulating the data. for example, how do you detect and deal with adding the same item to the cart more than once? with an array, you can just use isset() to detect if the item id is already in the cart. with concatenation, you must search though the string to find a match.
  9. i'm guessing the answer is 42?
  10. external data can be anything and cannot be trusted. you have to validate all external data before using it, so, you should submit/pass a minimum of information through a form. by using a hidden field, you will have to validate the original data and then re-validate all the hidden field data before using it. when items are selected, the item id (sku) and quantity should be the only information that gets submitted and should be stored in a 'cart' on the server, either in a session array variable or in a database table. you would use or display the server-side cart information as needed. when an order is finalized/finished, you need to persistently store the items making up that order, in a database table. to display or print a packing slip, you would query for and retrieve the item information for the correct order number.
  11. forget about the mysqli extension when updating old code, especially when there's external/unknown data being put into the sql query statement. use the much simpler and more consistent php PDO extension instead. after you make the connection using the PDO extension, in $pdo, the following are some usage examples - a query that doesn't have any external/unknown data being put into it // form the sql query statement $sql = "your sql query statement here..."; // execute the query $stmt = $pdo->query($sql); // for SELECT queries, fetch the data into an appropiately named php variable // for a query that will match at most one row $some_descriptive_var = $stmt->fetch(); // for a query that will match a set of zero or more row(s) $some_descriptive_var = $stmt->fetchAll(); // use the variable holding the data at the appropiate place in your html document. if the query didn't match any data, the variable will be a boolean false/empty() value. for a query that does have external/unknown data being put into it, you need to use a prepared query, with a ? place-holder in the sql query statement for each data value, then supply the data when you execute the query. // form the sql query statement $sql = "your sql query statement here..."; // prepare and execute the query $stmt = $pdo->prepare($sql); $stmt->execute(supply an array of the variable(s) holding the data values here...); // the code dealing with the result from a SELECT query is the same as above when converting an old query that has variable(s) in the sql query statement, you would remove the variable, any single-quotes, {}, and concatenation dots associated with the variable from the sql query statement, and replace each variable with just a ? place-holder. the variable(s) that were removed would be supplied as an array to the ->execute(...) method call. you would also remove, rather than convert, any ..._escape_string() functions in old code. when you make the connection, set emulated prepared queries to false (you want to run TRUE prepared queries when possible), error mode to exceptions, and set the default fetch mode to assoc (so that you don't have to specify it in every fetch statement, but can override it when necessary.) here is some typical connection code - $DB_HOST = ''; // db hostname or ip address $DB_USER = ''; // db username $DB_PASS = ''; // db password $DB_NAME = ''; // database name $DB_ENCODING = 'utf8'; // db character encoding. set to match the character encoding of your db tables $pdo = new pdo("mysql:host=$DB_HOST;dbname=$DB_NAME;charset=$DB_ENCODING",$DB_USER,$DB_PASS); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // set the error mode to exceptions $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); // run real prepared queries $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC); // set default fetch mode to assoc by using exceptions to handle database statement errors (the connection always uses an exception for an error, the above setting applies to query, prepare, and execute statements), you can eliminate any existing error handling logic, rather than to convert it. in most cases you should just let php catch any exception, where it will use its error_reporting, display_errors, and log_errors settings to control what happens with the actual error information. the only time you would need to have a try/catch block in your code to catch and handle a database exception is when inserting/updating duplicate data. this is a recoverable error. your catch logic would detect if a duplicate key error occurred (requires setting the database table column(s) as a unique index, if they are not already), and setup a user error message indicating what was wrong with the data that was submitted. if the error is not for a duplicate key, you would re-throw the exception and let php catch and handle it.
  12. here's a list of things i saw in the posted code - 1. don't put php variables inside of double-quotes if they are the only thing in the string. 2, don't use or die() for error handling. use exceptions and in most cases let php catch the exception. note: your use of mysqli_error(...) in the connection code won't work because there's no connection to use. 3. don't unconditionally output database errors onto a web page (this will go away when you get rid of the or die() logic.) 4. don't run queries inside of loops. learn to do JOIN queries. 5. if your code is tabbed that far over because it is located inside your html document, you need to put the php code that's responsible for getting/producing data before the start of your html document, fetch the data into appropriately named php variable(s), then use those variable(s) in the html document. 6. handling the negative/failure case is usually shorter then the positive/successful case. if you invert the logic tests and handle the negative/failure condition first, your code will be clearer. you won't have logic for the negative/failure case 10's/100's of lines later in the code. 7. don't use loops to fetch what will be at most one row of data. just directly fetch the single row of data. 8. don't put static calculations inside of loops. the various date values shouldn't change during one report (where they are at now, they will if the request spans midnight.) put them before the start of the loop. 9. don't put quotes around numbers. 10. don't selected things that are not used and don't create variables that are not used (given the amount of code, the cases i saw of this may not be accurate.) 11. if you are looping to do something (should go away with JOINed queries), don't evaluate count() statements in the loop. determine the loop count, once, before the start of the loop. 12. doing some of these things will simplify variable naming. you won't have to think up unique names for variables because you will only have one instance in the code. 13. the $AffID is probably from external/unknown data. you should NOT put eternal/unknown data directly into an sql query statement. use a prepared query, with a place-holder for each data value, then supply the data when the query gets executed. switching to the much simpler php PDO extension will make using prepared queries easy compared to the php mysqli extension.
  13. yes, but you are trying to upload 12M bytes. your form processing code, after detecting that a post method form was submitted, first needs to detect and handle the condition in item #3 in my list above. you should detect that the $_FILES array is empty and set up an appropriate user error message, than skip trying to process any $_FILES or $_POST data since there isn't any. you should use an array to hold the validation errors (this is not the same as your array holding the defined error messages.) as you test and validate the submitted data, store the errors into an array variable. this variable then also serves as an error flag. if the array is empty, there are no errors and you can use the submitted data. if the array is not empty, there are errors. to display the errors, you would output the content of this array at the appropriate point in your html document.
  14. if you are still getting the first error you listed - ... POST Content-Length of 12263648 bytes exceeds the limit of 8388608 bytes..., and you tried to set the post_max_size setting to be more than 8M Bytes, something prevented the change from working. either the php.ini that you changed isn't the one that php is using, there's a setting that's overriding the one you change (a local php.ini), there's a syntax error in the php.ini above the point you changed that's preventing the file from being fully parsed, the line you changed is in some commented out code or is using a value that isn't valid. add a phpinfo(); statement to the top of your .php file and check what the - Loaded Configuration File value is and what both the local and master post_max_size setting is. also, check if the file_uploads setting is ON. for reference, here are the things that can cause the $_FILES array to be empty - 1. One of several possible problems with the html form - not a post method form, missing the enctype attribute, missing a type='file' field, the form field isn't inside the form, a misnaming between the form field and the php code, broken html markup, ... 2. Uploads are not enabled on the server. 3. The total size of the submitted post data exceeds the post_max_size setting. In this case, both the $_POST and $_FILES arrays will be empty. 4. The $_FILES array is being referenced without first detecting that a post method form was submitted.
  15. you only need one form field per item. use a meaningful name for the field, such as qty, and use the item id as the field's array index value - name='qty[item id goes here]'. in the form processing code, use a foreach() loop. this will give you the item id and the submitted quantity for the id. to remove empty items use array_filter() with no call back function (empty strings and zeros are false and will be removed.) lastly, you need to insert a separate row in your table for each item and you need to use a prepared query, with place-holders in the sql query statement for each value, then supply the values when you execute the query. you would prepare the query once, before starting to loop over the data, then only get each set of values and execute the query inside of the loop.
  16. before the start of your html document, query for and retrieve the data you want in the order that you want it, storing the two rows of data in an appropriately named php array variable. loop over the data at the point in your html document where you want to display the content and output the dynamic parts using php code.
  17. 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.
  18. your code is probably executing the connection code again, which is recreating the table. it's generally not a good idea to have table deletion/creation queries being unconditionally executed.
  19. 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.)
  20. if you fix what's causing the first error message, the second one will go away. why do you have two session_start() statements?
  21. 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.
  22. here's code (partially tested only) that uses the suggestions above and from the previous thread - <?php //mySQL database config require "config.php"; // Define all variables and initialize them as 'empty' $errors = []; // an array to hold error messages and serves as an error flag $post = []; // an array to hold the trimmed input data // Process data when the form is submitted. if($_SERVER["REQUEST_METHOD"] == "POST") { // assuming the $_POST field names in the original code are accurate, the inputs to this code are - // name, username, password, and password2 $post = array_map('trim',$_POST); // get a trimmed copy of the $_POST data (if any of the form fields are arrays, you need a recursive trim call-back function in this line instead of php's trim() function) //Name check if(empty($post["name"])) { $errors['name'] = "Please enter a name."; } // Validate 'Username' if(empty($post["username"])) { $errors['username'] = "Please enter a Username."; } // Validate Password if(empty($post["password"])) { $errors['password'] = "Please enter a password."; } else { if(strlen($post["password"]) < 6) { $errors['password'] = "Password must have at least 6 characters."; } } // Validate Confirm Password. if(empty($post["password2"])) { $errors['password2'] = "Please confirm your password"; } // check password and confirm password if(empty($errors['password']) && empty($errors['password2']) && $post['password'] != $post['password2']) { $errors['password_confirm'] = "Password and confirmed password do not match."; } // if no validation errors, use the submitted data if(empty($errors)) { $sql = "INSERT INTO users (name, username, password) VALUES (:name, :username, :password)"; $stmt = $pdoConn->prepare($sql); // use a 'local' try/catch to handle errors from this query try { $stmt->execute([ ":name"=>$post['name'], ":username"=>$post['username'], ":password"=>password_hash($post['password'], PASSWORD_DEFAULT) ]); } catch (PDOException $e) { $er=$e->errorInfo(); // get the error information if($er[1] == 1062){ // duplicate key error number $errors['username'] = "The username is already in use."; } else { throw $e; // re-throw the pdoexception if the error is not handled by this logic } } // if no errors, the insert was successful if(empty($errors)) { header("Location: ../index.php"); exit; } } }
  23. the posted form processing code contains a php syntax error, as indicated by the color highlighting stopping. there's no way it is running. only one one of the form field names matches between the php code and the form, so even if the form processing code runs, it is not operating on the correct field names. at a minimum, you need to set php's error_reporting to E_ALL and set it in the php.ini on your system. you can put the setting into your code but since you code never runs when there is a php syntax error, you won't see the error unless the setting is set in the php.ini.
  24. to do what you are asking, just make the username column a unique index, forget about the SELECT query, just run the INSERT query, and test if there was a duplicate key error. if there is, it means that the username already exists. this alone will eliminate a 1/4th of the code. in addition to the suggestions already given in a previous thread, this code is filled with unnecessary and repetitive logic, mistyped and non-existent variable names (which is why some of the code isn't running.) you even have a backward logic test that would only run the INSERT query if all the variables are empty. you need to use the simplest and most general purpose code that accomplishes a task. what you are doing now is creating a wall of code which is hiding the mistakes. you have a 'cannot see the forest for the trees' problem. some more suggestions - 1) forget about making discrete variables for every form field and every error. use arrays instead. one for the trimmed input data and one for the errors. 2) trim all the input values at one time. if i/someone has time they will post an example that takes only one line of code. 3) when you validate the inputs, store any error messages in an array. this array is also an error flag. if the array is empty, there are no validation errors. if the array is not empty, there are errors. after all the validation tests, if the array is empty, you can use the submitted data. in your html document, if the array is not empty, display the errors by displaying the contents of the error array. 4) stop creating variables for nothing. in this thread and your other current thread, you have variables that don't exist and typo mistakes in variable names. by using an array to hold a trimmed copy of the input data, then using just this array in the rest of the code, hopefully it will cut down on these type of mistakes.
  • 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.