-
Posts
5,536 -
Joined
-
Days Won
192
Everything posted by mac_gyver
-
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.
-
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.
-
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.
-
Safe to use two forms and hidden inputs?
mac_gyver replied to StevenOliver's topic in PHP Coding Help
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. -
i'm guessing the answer is 42?
-
Safe to use two forms and hidden inputs?
mac_gyver replied to StevenOliver's topic in PHP Coding Help
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. -
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.
-
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.
-
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.
-
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.
-
Submit large form created with select statement
mac_gyver replied to Adamhumbug's topic in PHP Coding Help
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. -
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.
-
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.
-
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.)
-
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.
-
Shall I use mysqli_stmt_free_result($stmt) Or Not ?
mac_gyver replied to phpsane's topic in PHP Coding Help
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 } -
How to split a search strings and put it into a prepare statement?
mac_gyver replied to bbmak's topic in PHP Coding Help
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.- 6 replies
-
- search string
- split
-
(and 1 more)
Tagged with:
-
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.
-
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.
- 6 replies
-
- 1
-
-
- php
- fatalerror
-
(and 1 more)
Tagged with:
-
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.
- 6 replies
-
- 1
-
-
- php
- fatalerror
-
(and 1 more)
Tagged with:
-
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.
-
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.
-
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];
-
$row['entry_name'] == $name; ^^^ this is a comparison, not an assignment, so one would expect nothing to be altered.