Psycho
Moderators-
Posts
12,157 -
Joined
-
Last visited
-
Days Won
129
Everything posted by Psycho
-
That question cannot be answered. The appropriate number of "queries" (or what I think you mean is how much data should be stored) is completely dependent upon the needs of the application. If the needs of the application requires 5 queries or 500 queries then that is what it takes. To address your specific need, you are wanting to store a user's cart. There are a few different solutions and which one you choose can depend on many factors. You can use sessions, but they will only persist for the user's session (obviously). This is pretty easy to manager. You can store the info in cookies, which will persist across sessions. But, if a user saves a cart it would only be available to them on that same pc. If you want carts to persist across sessions and PCs then you will want to store them in the DB and ties to a user login. There is no right or wrong method - it depends on which one meets your specific needs. Many sites use several methods.
-
Then you should store the cart info in the database or in SESSION data. But, to answer your question directly you can pass variables from the client to the server using Javascript by performing an AJAX request - which I wouldn't suggest for cart info.
-
A lot of developers try to avoid tables because they were over used as a formatting control for so many years. But, a table is the right construct for displaying tabular data and I think that applies here. Also, here are a couple other suggestions: 1. Don't use mysql_real_escape_string() to esacpe values that are supposed to be numbers - use an appropriate function to force the value to a number or typecast as a number. In this case you want to convert $name to an inteeger - so you can use intval(). 2. No need to use "(strlen($name)-5" as the third parameter in your substring call $id = substr($name, 5, (strlen($name)-5)); If you leave the third parameter empty it will get the entire string starting from the start index. Taking into consideration #1 and #2 you could just have $id = intval(substr($name, 5); and then not use mysql_real_escape_string() 3. Don't run queries in loops it is terribly inefficient. So, get all the values you want to use for your queries and run ONE query 4. Put all of your "cart" items into a sub array using just the ID as the index, e.g. $_SESSION[cart][3], $_SESSION[cart][8], etc. Rather than concatenating 'cart' and the id as the key - will make things MUCH simpler. (The code below assumes this has been done) 5. No need to iterate over the values to exclude the ones with a 0 value. Just use array_filter() There were other things as well, but I have other things to do. Give this a try function cart($recPerRow=4) { //Force the values to be integers $valuesAry = array_map('intval', $_SESSION['cart']) //Remove zero (false) values $valuesAry = array_filter($valuesAry); if(count($valuesAry) > 0) { $valuesStr = implode(', ', array_map('intval', $values)); $query = "SELECT id, name, price FROM products WHERE id IN ($valuesStr) ORDER BY id, name"; $get = mysql_query($query); $count = 0; while ($row = mysql_fetch_assoc($get)) { $count++; //Open new row if needed if($count % $recPerRow==1) { echo "<tr>\n"; } $quantity = $valuesAry[$row['id']]; $price = number_format ($row['price'], 2); $sub = number_format($row['price'] * $quantity, 2); echo "<td>"; echo "{$row['name']} x {$quantity} * €{$price} = €{$sub}"; echo "<a href='cart.php?remove={$row['id']}'><img src='subtract.png' border='0' style='height: 20px; width: 35px' ></a>"; echo "<a href='cart.php?add={$row['id']}'><img src='pluss.png' border='0' style='height: 20px; width: 35px' ></a>"; echo "<a href='cart.php?delete='{$row['id']}'><img src='delete.png' border='0' style='height: 20px; width: 50px' ></a>"; echo"</td>\n"; //Close new row if needed if ($countxx % 4 == 0) echo "<div style='clear:both'></div>"; } if($count%$recPerRow==0) { echo "</tr>\n"; } } @$total += $sub; } }
-
How Can Site Get Hacked If You Protect All Get And Post Inputs ?
Psycho replied to Eritrea's topic in Application Design
Um, "abc12" IS a string! From a programmatical sense anything within quotes is a string. Even "123" is a string. In fact, every piece of data passed via POST/GET is a string. If PHP if the language you've had the most experience with then variable types is probably something you're not very familiar with. PHP is a loosely types language. This means that when using values in various means, the PHP parser can interpret if the value should be treated as test an integer a float a Boolean, etc. For example: $foo = 2 + '3'; //5 is perfectly fine in PHP (although I would never do that). But many other languages would not allow that since the '3' is defined as a string. PHP sees that the 2 is a number and sees the '3' as a string, but because you are trying to add the two values it converts the string of '3' to the number 3 on-the-fly and performs the addition. By the same token, PHP can convert a number into a string if the process requires it $foo = 2 . '3'; //23 So, the is_string() function is specifically used to check if the value is of the string TYPE is_string('abc'); //true is_string('123'); //true is_string(123); //false If you want to ensure that a variable only contains alphabetical characters then use ctype_alpha(). But, if you want to allow puntuation as well, you'll probably need to revert to regex.- 7 replies
-
- php
- sql-injection
-
(and 2 more)
Tagged with:
-
Was it really necessary to post the entire script rather than just the relevant sections? It's your prerogative, but many people are turned off by people that do that and are less likely to respond - I almost didn't Anyway, you are always creating a jpg image so, just add .jpg to the end of the md5() name $new_file = md5($_FILES["image_upload_box"]["name"]) . '.jpg'; Also, note that using an MD5() hash on the name will not prevent problems if users upload files with the same names. Since you can't reverse the hash into the name anyway, the value used to create the hash is not important. You could append a timestamp and/or random number to the value being hashed to prevent issues with duplicates.
-
So, what was the problem? I tested the code I provided - so I know it worked. When I test using the value you state I get the appropriate message. Perhaps you were passing "Mastercard" rather than "MasterCard" in the post data? If you noticed I had added logic in the code I provided in case the card type was not valid as well. You should definitely be verifying that the card type is a valid one as well. As it was, your original code would pass any values that passed the initial, non-card specific checks if the card type was not one of the ones you coded for.
-
Looking at my MaterCard, that RegEx is wrong anyway (based upon how I think you wanted it to work) $pattern = "/^([51|52|53|54|55]{2})([0-9]{14})$/"; The {2} is looking for two matches. Since you had 51, 52, 53, 54, or 55 followed by 14 other digits.I think you were trying to match any of those pairs twice followed by 14 digits. But, you should only match one of those pairs (as ManiacDan has above). EDIT: Also, since you are already doing validations that the input is only numbers, do you really need to verify that the characters at the end are numbers? Or maybe, you don't need to do those general validations up front since your regex's should capture those problems anyway. This is MUCH more efficient $ccNumber = trim($dataError['cnumber']); $ccType = trim($dataError['ctype']); if(empty($ccNumber)) { $errormsg['cnumber'] = 'Credit Card Number is required!'; } else if(!ctype_digit($ccNumber)) //Don't use is_numeric because it allows decimals! { $errormsg['cnumber'] = 'Card Number must be numeric!'; } else { //Number passed general validations, perform specific validation based on type switch($ccType) { case "AmericanExpress": $pattern = "/^((34)|(37))\d{13}$/"; $ccType = 'American Express'; break; case "Discover": $pattern = "/^6011\d{12}$/"; break; case "MasterCard": $pattern = "/^((51)|(52)|(53)|(54)|(55))\d{14}$/"; break; case "Visa": $pattern = "/^4\d{12,15}$/"; break; } if(!isset($pattern)) { $errormsg['cnumber'] = 'Select a valid Credit Card type!'; } elseif(!preg_match($pattern, $ccNumber)) { $errormsg['cnumber'] = "Not a valid {$ccType} Card Number!"; } }
-
Argh! Way, way too many elseif's there. But, I don't understand your question since I don't see anything in the conditions that would exclude the number 4. For matercard this is what you have else if($dataError['ctype'] == "MasterCard") { $pattern = "/^([51|52|53|54|55]{2})([0-9]{14})$/"; if(!preg_match($pattern,$dataError['cnumber'])) { $errormsg['cnumber'] = 'Not a valid MasterCard Card Number!'; } } The way I read that is that the regex is looking for a number that begins with two pairs from 51-55, (e.g. 5151, 5154, 5453, etc.) and is then followed by 14 additional digits. If that match is true then you would get the error condition. Maybe I am missing it, what in that code makes you think the number 4 should be excluded?
-
images_list.php (a file to define all the available images and the image directory) <?php $imageDir = '/images/'; $images = array( '1' => 'image(1).JPG', '2' => 'image(2).JPG', '3' => 'image(3).JPG' ); ?> index.php (dynamically create the links based upon the defined images) <?php include(images_list.php); echo "<table width='30%' border='0' cellpadding='7' cellspacing='5'>\n"; echo "<tr>\n"; foreach($images as $imageID => $imageName) { echo "<td><a href='http://localhost/image.php?view={$imageID}'><img src='{$imageDir}{$imageName}' width='200' height='170' /></a></td>\n"; } echo "</tr>\n"; echo "</table>\n"; ?> image.php (dynamically show the image comparing to the images list) <?php include(images_list.php); $imageID = isset($_GET['view']) ? intval($_GET['view']) : false; if($imageID===false || !in_arraY($imageID, $images)) { echo "No image selected!"; } else { $imageName = $images[$imageID]; echo "<img src='{$imageDir}{$imageName}' WIDTH='500' HEIGHT='400' />n\"; } ?> Note that using full size images as previews is a based idea as it still requires the user to download the full images. You should instead create smaller versions of the full size images and use those in the previews. Using the process above you could just create a subfolder (e.g. 'thumbs') and put the smaller images in there. They should have the same name as the full-size. Then, just change the index.php page to use the subfolder when creating the previews.
-
Well, you should definitely rethink the process, but the problem is that your parameter name is "view" <td><a href="http://localhost/ima...hp?view=1"><img src="/images/image(1).JPG" width=200 height=170/></a></td> But, in your processing code you are checking "view1" if ($view1 == 1)
-
OK, using the field format above, this is one solution for the processing script: //Create temp string to hold insert data $insertClauses = ''; foreach($_POST['item'] as $id => $qty) { $insertClauses[] = " WHEN '$id' THEN '$qty' \n"; } //Create single UPDATE query for all records $query = "UPDATE items SET qty = CASE id $insertClauses END"; $result = mysql_query($query); The resulting query would look like this: UPDATE items SET qty = CASE id WHEN '1' THEN '25' WHEN '2' THEN '205' WHEN '3' THEN '2' WHEN '4' THEN '155' WHEN '5' THEN '62' END
-
Well, I'm still unsure of what you are trying to do. You first show some code that will output some data from a query. But, then you ask about how you would access some values from POST data. I'm really not understanding what one has to do with the other. But, based upon bits and pieces of what you've posted I will make an attempt at deciphering what I think you want to do. I think you want to 1) create a form of all the items that the user can edit, then 2) you want the user to POST that form and 3) you want to process that form into appropriate UPDATE queries based upon what the user changed. OK, let's say the table contains three fields: id, name, and qty and you want to allow the user to change the quantity. I would first create the form like so $query = "SELECT id, name, qty FROM items"; $result = mysql_query($query); while($row=mysql_fetch_array($result)) { echo "<tr>\n"; echo "<td width=\"80px\"></td>\n"; echo "<td><input type=\"text\" size='45' name=\"item[{$row['id']}]\" value=\"{$row['qty']}\"></td>\n"; echo "</tr>\n"; } Now, there is no direct way to know what values changed and which ones did not. You could implement some JS code to set a hidden field or something, but that's a poor solution. Instead you can just run the update query(ies). If nothing changed then no changes are made to the DB. But, the problem here is that you don't want to run unnecessary queries. Personally, I would make a decision based upon how often the page would be used and how many potential records there are. If it is not used all that often (many, many times a day) and there aren't going to be hundreds/thousands of records I would probably just iterate through each record and run an UPDATE query. But, the better method would be to either 1) Run a SELECT query for all the records and process them to figure out which ones changed or 2) create a single update query for all the records. Option #2 is probably better, but is a little complicated. I'll do some research to see if I can find the correct format.
-
Look at the HTML source that is being produced and the problems would be clearly evident. The output would look something like this: <td><a href="mailto:value_of_email_t</a></td> <td><a href="value_of_url_t</a></td> You are opening the href parameter using a quote mark and then adding the dynamic value. But, you never 1) close the href parameter with a quote, 2) close the opening A tag or 3) provide a value to be between the opening/closing A tags (i.e. text to be the actual hyper-link. If you want the same value to be the href location AND the displayed hyperlink, this should work (assuming the values are valid for this purpose) <td><a href="mailto:<?php echo $record['email_t'];?>"><?php echo $record['email_t'];?></a></td> <td><a href="<?php echo $record['url_t'];?>"><?php echo $record['url_t'];?></a></td> Or my preference echo "<td><a href='mailto:{$record['email_t']}'>{$record['email_t']}</a></td>\n"; echo "<td><a href='{$record['url_t']}'>{$record['url_t']}</a></td>\n";
-
What did you mean by "loading" them? Exactly how are you using the names of the files? Are you using them within an IMG tag, are you sending the image as an image object, or what? The solution could be that you need to enclose the output in quote marks. But, more likely, I'm guessing can get what you want by simply using urlencode(); But, it would help to see how you are actually using it.
-
Here is some sample code for the two possible solutions above. I went ahead and incorporated the two queries for solution 2 into a single query statement with both the queries. I have not tested these so there may be some syntax errors, but the logic should be sound Option 1 $top_count = 10; //Query ALL domains and their counts $query = "SELECT domain, COUNT(domain) AS domaincount FROM domain_table GROUP BY domain ORDER BY domaincount DESC"; $result = mysql_query($query); $other_count = 0; while($row = mysql_fetch_assoc($result)) { if($top_count > 0) { //Display top domain and count echo "{$row['domain']}: {$row['domaincount']}<br>\n"; $top_count--; } else { //Calculate 'other' total $other_count += $row['domaincount']; } } //Display 'other' total echo "Other: {$row['domaincount']}<br>\n"; Option 2: $top_count = 10; //Query only the top 10 domains and run second //query with total count of ALL domains $query = "SELECT domain, COUNT(domain) AS domaincount, (SELECT COUNT(domain) FROM domain_table) AS totalcount FROM domain_table GROUP BY domain ORDER BY domaincount DESC LIMIT {$top_count}"; $result = mysql_query($query); while($row = mysql_fetch_assoc($result)) { if(!isset($other_count)) { $other_count = $row['totalcount'] } //Display top domain and count echo "{$row['domain']}: {$row['domaincount']}<br>\n"; //Reduce other_count by this domains count $other_count -= $row['domaincount']; } //Display 'other' total echo "Other: {$row['domaincount']}<br>\n";
-
I think you could do this one of two ways. Which way I would choose would be based upon the total number of records. If you don't have a "lot" of records (i.e. hundreds) I would use one query to return the count for all domains and then process all of them: displaying the count for the top n records and then using the remaining records to get the other count. However, if you have a lot of records it may be more efficient to do two queries: one to get the top domains by count with a LIMIT clause and a second query to get the total count. So, option one would be to remove the LIMIT cause on your current query and option two would be to run a second query to get the total count (then subtract the counts of the top records). NOTE: Don't use "COUNT(domain)" in the ORDER BY clause - you already did that to get the dynamic value of "domaincount" so no need to do that calculation twice.
-
Yeah, I'm having a hard time understanding what you are after. Can you please elaborate?
-
OK, I rewrote your code in about 5 minutes in a much more logical and sound format. I don't have your database or other files needed to even test the code. So, I missed changing one single variable name. You sure put me in my place. If you are not interested in learning good standard coding practices, that's your perogative. I'll just remember not to provide any help to you in the future.
-
Just because somethign works and is easier does not mean it is the correct way. There are plenty of un-strict behavior that is changes in later versions of PHP. Best to use proper coding now than to have a lot of code break with newer versions of PHP.
-
You should NOT tell the user that the username or password do not match. Doing that gives a malicious user information that they can use to exploit the system. If you are not going to track invalid login attempts against usernames then you can simply do a query usign both the username AND the password. If there is no match then prevent login. You would only do a SELECT using just the username THEN compare the password if you want to keep track of invalid logins. Also, do NOT store the password in session data. There is no (good) reason to do so. There are several other problems as wll: not using a salt, not escaping the username, etc. Here is a much more logical flow: Edit: removed code since OP is not appreciative of help given
-
1. Separate your logic (PHP) from the output (HTML). Out all the core PHP logic at the top of the page and create variable of dynamic output. Then just echo those in the HTML. 2. You have invalid HTML code, the output of the radio buttons has surrounding table row and cell tags, but it is not within a table. 3. Your radio button options names don't make sense. All radio buttons in a group should have the same name. Yours all have unique names. So, they won't work correctly. 4. Put the DB connection code into a separate file and include in the pages where you need it rather than copying it into multiple pages db_connect.php <?php $dbhost = 'localhost'; $dbuser = 'fakeuser'; $dbpass = 'fakepass'; $con = mysql_connect($dbhost,$dbuser,$dbpass); ?> index.php <?php //Connect to DB include('db_connect.php'); $set = mysql_query('SHOW DATABASES',$con); $dbs = array(); while($db = mysql_fetch_row($set)) { $table = $db[0]; $tableButtons .= "<input type='radio' name='table' value={$table}>{$table}<br>\n"; } ?> <html> <body> <form name="form1"action="deletedb.php" method="post"> Select a table:<br> <?php echo $tableButtons; ?> <br><br> <input type="submit" value="DeleteDB"> </form> </body> </html> deletedb.php <?php //Connect to DB include('db_connect.php'); $dbName = trim($_POST['table']); $query = "DROP DATABASE $dbname"; $result = mysql_query("DROP DATABASE $dbname",$con); if($result) { $message = "Database dropped, ur data's gone!" . "<br>"; } else { $message .= "Error deleting database: " . mysql_error() . "<br>"; } ?> <html> <body> Deleting database: '<?php echo $dbName; ?>' <br><br> <?php echo $message; ?> </body> </html> However, I've left off a lot of validation logic I would add to prevent errors.
-
Php Loop In A Loop Optimization Help Request
Psycho replied to Failing_Solutions's topic in PHP Coding Help
I haven't read through all the code in detail, but I think there is an easy solution: array_chunk() Just dump each record as a sub array into the main array. Then use array_chunk() to split the array into sub-arrays containing 5 records each. -
Yeah, my terminology may have been lacking as the records aren't really "consumed". Thanks for clarifying. And, although you *could* achieve the desired results using mysql_data_seek() I'm sure you aren't proposing that this is a scenario where it would make sense to do so.
-
Not to mention the fact that you are putting code within code: echo implode('<tr><td><input type="radio" name="<?php echo $dbs; ?>" value="<?php echo $dbs; ?>"</td></tr>' , $dbs) . "<br>"; That line of code makes no sense. Plus, there is no closing > for the input field. If I think I understand what you are trying to accomplish, you need to do a foreach() loop foreach($dbs as $db) { echo "<tr><td><input type='radio' name='{$db}' value='{$db}'></td></tr>\n"; }
-
Is This How To Send Email And Update Mysql At The Same Time?
Psycho replied to dev-ria's topic in PHP Coding Help
Well, let's think about this for a moment. You only want both processes to occur if both succeed. Well, that's not logically possible. You have to do one before the other. So, your only option is to do one first. If it fails then don't do the second. If the first process succeeds then the second one fails then you need to undo the first process. If you send an email there is no way to undo that, so your only option is to start with the DB query. I believe in MS SQL there is a way to do a "tentative" query where it verifies that the query will execute and then you can do something else before executing it. But, assuming you are using MySQL, I don't know if that is possible. So you could do something like this: 1. Before doing the update query, do a select query on the record and store the current values 2. Perform the update query 3a. If the update query fails then stop 3b If the update query succeeds then attempt to send the email 4a If the email succeeds, stop 4b If the email fails, the run a new update query to set the value back to what they were previously using the data from step 1 But, really, this is probably all overkill. If your code is clean and logically built there is very little chance of either the email or query failing short of the DB or email servers going down. I'd just make a determination of which process is more important. I would think it would be worse for the email to be sent if the DB wasn't updated rather than the converse. So, I would do the DB update first.