I am working on a shopping cart website for a university project and need some help.
The site is currently under production at http://www.cutecupcak.es.
At the moment, each product has a url of something like http://cutecupcak.es/product.php?id=11, but I want it to be something like http://cutecupcak.es/product.php?id=chocolate_cupcake.
This is the code we have been given to make this work.
if(isset($_GET['id'])) {
$id = $_GET['id'];
$result = mysql_query("SELECT * FROM `CAKE` WHERE `cake_id`=($id)");
}
What do I need to change to get the cake_name to show rather than the cake_id?
Generally, if you want to reference your products by a name instead of id - you should add a new column (I always name it as "slug") with an UNIQUE key. Then, when product is added or edited, based on its name you generates new value for the slug column. For example - from "Chocolate Cake" you will create "chocolate_cake". Then you have to check if the slug is unique - and if not - resolve conflict somehow (e.g. "chocolate_cake_1").
If you have all this set up - just select the appropriate product by unique slug:
$result = mysql_query("SELECT * FROM `CAKE` WHERE `slug`='" . mysql_real_escape_string($_GET['id']) . "'");
And - obviosuly - use mysqli instead of deprecated mysql functions.
http://php.net/manual/en/mysqli.query.php
You can put the name in the url, which should be quite simple, since you have both the name and the id in your database and you can search by and use both.
Both name and id
But I would advise against it. Product names can change a little, and changing it means that the old link wont work anymore.
I would create an url like this:
http://cutecupcak.es/product.php?id=11&name=chocolate_cupcake
or rather even:
http://cutecupcak.es/product/11/chocolate_cupcake
These urls can be indexed safely. You retain the numeric id, which you can use to lookup the number. The name is in the url as well, which is good for readability and for SEO (search engine optimization), but the name has no actual meaning. You can safely ignore it, because you got the number. Therefor all previously indexed and linked urls will remain valid after you change the name.
I would choose to use dashes instead of underscores in the product name. I believe chocolate-cupcake and chocolate+cupcake are both indexed better than chocolate_cupcake, but my information on this topic may be a bit stale.
mysql? Parameters!
I also would advise you to no longer use mysql_*, and start using PDO or mysqli. Both allow the use of parameterized queries. This allows you to pass an id or name to a query in a safe and transparent method. Safer, cleaner and better performing than using mysql_real_escape_string or functions like that. It's especially safer, because once you become accustomed to using parameters, you will start passing all variables as parameters. While you can forget to escape a variable in your current query, you cannot possibly forget to escape a variable, because it doesn't need escaping.
Try something like this:
if(isset($_GET['id'])) {
$id = $_GET['id'];
$result = mysql_query("SELECT * FROM `CAKE` WHERE `cake_name`=(". mysql_real_escape_string($id). ")");
}
Note: I also added mysql_real_escape_string, as not doing that poses a huge SQL injection risk.
I think this just changes to:
$result = mysql_query("SELECT * FROM `CAKE` WHERE `cake_name`=($id)");
The Following is a blueprint to what you have to do:
1- In your table you should set cake_name field to be unique.
2- Your sql query should be:
$result = mysql_query("SELECT * FROM `CAKE` WHERE `cake_name`=($id)");
3- Change the links found of your products list to obtain the cake_name value instead of the numeric id.
Related
I have a table filter feature in PHP club membership webpage. I made it so the user can filter the table and choose which members to display in a table. For example, he can choose the country or state where the member is from then hit display. I am using a prepared statement.
The problem is, I need to use wildcards to make the coding easier. How do I use a wildcard in PHP MySQL query? I will use wildcards for example if the user does NOT want specific country but instead he wants to display all members from all countries.
I know not specifying the WHERE country= will automatically select any countries but I already constructed it so each controls like the SELECT control for country already has a value like "CA" or "NY" and "*" if the user leaves that control under "All Countries". This value when submitted is then added to the query like:
$SelectedCountry = $_POST["country"];
sql .= " WHERE country=" . $SelectedCountry;
But the problem is using WHERE country=* doesn't seem to work. No errors, just doesn't work. Is "*" the wildcard in PHP MySQL?
The * is not a wildcard in SQL when comparing with the = operator. You can use the like operator and pass a % to allow for anything.
When doing this the % should be the only thing going to the bind. $Bind_country = "'%'"; is incorrect because the driver is already going to quote the value and escape the quotes. So your query would come out as:
WHERE country ='\'%\''
The = also needs to be a like. So you want
$bind_country = '%';
and then the query should be:
$sql = 'select * from table where country like ?';
If this were my application I would build the where part dynamically.
Using * in WHERE clause is not right. You can only give legit value. For example:
// looking for an exact value
SELECT * FROM table WHERE column = 'value'
// you can also do this when looking for an exact value
// it works even if your $_POST[] has no value
SELECT * FROM table WHERE column = 'value' OR '$_POST["country"]' = ''
// looking for a specific or not exact value
// you can place % anywhere in value's place
// % denotes the unknown characters of the value
// it works also even if your $_POST[] has no value
// results will not be the same when you're using AND or OR clause
SELECT * FROM table WHERE column LIKE '%val%'
I think below link can solve your problem.
Just have a look and choose what you need.
Thanks.
http://www.w3schools.com/sql/sql_wildcards.asp
$content is a variable with a 'detailed description'.
product_id is column which might contain a substring of the detailed description ($content) in a MySQL table called products
I am trying to create a select statement that would find a record if the product_id is CONTAINED in the $content variable. Then I want to update another table called receive_sms with the url field from the SELECT staement
Researching on the website I have come up with the following.... But it doesn't work
$mysqlic = mysqli_connect("testsms.cloudaccess.net", "username", "password", "testsms2");
$prod_res=mysqli_query($mysqlic,"SELECT url from products
WHERE %product_id% LIKE %$content%");
mysqli_query($mysqlic,"INSERT INTO recieve_sms (comments) VALUES ('$prod_res')");
Any Ideas??
It should be:
$prod_res = mysqli_query($mysqlic, "SELECT url from products
WHERE '$content' LIKE CONCAT('%', product_id, '%')");
or:
$prod_res = mysqli_query($mysqlic, "SELECT url from products
WHERE LOCATE(product_id, '$content') != 0");
You need to put $content in quotes.
Actually, it would be better if you used a prepared query, then '$content' would become a placeholder ?.
After you query, you need to call mysqli_fetch_assoc() to get the column value:
$row = mysqli_fetch_assoc($prod_res);
$url = $row['url'];
Well, first of all, I don't understand why you're using wildcards on you field name. You want to check if a value is contained within the value of that field, consider changing this:
... WHERE %product_id% LIKE %$content%);
to
... WHERE product_id LIKE '%$content%');
Also, please, use prepared statements to avoid SQL injection. You're using MySQLi, which supports them.
EDIT
Also, the return of a mysqli_query is a MySQLi Resource. You'll have to fetch the results from the resource to gain access to the value you're looking for.
i have a row in my database with name "active_sizes" and i want filter my website items by size, for this, i use LIKE Condition in php :
AND active_sizes LIKE '%" . $_GET['size'] . "%'
but by using this code i have problem
for example when $_GET['size']=7.0 this code shows items that active_sizes=17.0
my active_sizes value looks like 17.0,5.0,6.5,7.5,,
thanks
Using comma-separated values in a single field in a database is indicative of bad design. You should normalize things, and have a seperate "item_sizes" table. As it stands now, you need a VERY ugly where clause to handle such sub-string mismatches:
$s = (intval)$_GET['size'];
... WHERE (active_sizes = $s) // the only value in the field
OR (active_sizes LIKE '$s%,') // at the beginning of the field
OR (active_sizes LIKE '%,$s,%') // in the middle of the field
OR (active_sizes LIKE '%,$s') // at the end of the field
Or, if you normalized things properly and had these individual values in their own child table:
WHERE (active_sizes_child.size = $s)
I know which one I'd choose to go with...
You don't state which DB you're using, but if you're in MySQL, you can temporarily accomplish the same thing with
WHERE find_in_set($s, active_sizes)
at the cost of losing portability. Relevant docs here: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_find-in-set
You Have % signs around your $_GET value. Combined with LIKE, this means that any string that simply contains your get value will be retuned. If you want an exact match, use the = operator instead, without the percentage signs.
This will solve your immediate issue:
AND active_sizes LIKE '" . mysql_real_escape_string($_GET['size']) . "%'
If you are using the database other than MySQL, use corresponding escape function. Never trust input data.
Besides, I'd suggest using numeric field (DECIMAL or NUMERIC) for active_sizes field. This will accelerate your queries, will let you consume less memory, create queries like active_sizes BETWEEN 16.5 AND 17.5, and generally this is more correct data type for a shoe size.
I have a function below which works perfectly, but now the client came back and asked that the number only be taken to do the search because most of his clients won't type in the suffix "h" or whatever it may be as per my example below:
38039 or 38039h
However he also said he only has one group of product codes which begin with "T" so they could be typing in "T760" in which case we would need the prefix.
My code below does a search on the exact product currently, can anyone help me work in these examples?
<?php
//Find Stock Value
function checkstock($prodCode) {
$prodCode = strtoupper($prodCode);
require '../../../../config.php';
$dbh = new PDO(DB_DSN, DB_USER, DB_PASS);
$sql = "SELECT * FROM isproducts WHERE prodCode = '".
$prodCode."' AND AllowSalesOrder = '1'";
$stmt = $dbh->query($sql);
$obj = $stmt->fetch(PDO::FETCH_OBJ);
$count = $stmt->rowCount();
echo ($count == 1 ?
ROUND($obj->FreeStockQuantity, 0) : 'Invalid product code '.$prodCode.'');
}
//Call Stock Function
checkstock($_POST['productcode']);
?>
Change the query to like below ?
SELECT * FROM isproducts
WHERE
(
prodCode='{$prodCode}' // for product with prefix or suffix
OR prodCode LIKE '{$prodCode}%' // without suffix
OR prodCode='T{$prodCode}' // without prefix
)
AND AllowSalesOrder = ''";
Wild-card by single character
OR prodCode LIKE '{$prodCode}_' // single character wild-card
It seems that you may have products with the same number but not the same suffix? like 8512n and 8512h ?
You could use LIKE '%$code%'
$sql = "SELECT * FROM isproducts WHERE prodCode LIKE '%".$prodCode."%' AND AllowSalesOrder = ''";
and I think its the more secure way in your case, so that all products containing the number will appear, regardless of suffix or prefix.
The above may return more than one product, so the user still has to choose which one it is he is actually looking for.
You can use % wild card for this kind of problem.
check this out....
http://www.w3schools.com/SQL/sql_wildcards.asp
it might be useful... :-)
In some of my code I use the following strategy:
# psuedo-code ... NOT intended for real use:
SELECT COUNT(*) FROM someTable WHERE someColumn = "{XXX}"
# If that returns exactly one than use the corresponding query
SELECT COUNT(*) FROM someTable WHERE someColumn LIKE "{XXX}"
# If that returns exactly one then use it
SELECT COUNT(*) FROM someTable WHERE someColumn LIKE "{XXX}%"
# If that returns exactly one then use it
SELECT COUNT(*) FROM someTable WHERE someColumn LIKE "%{XXX}%"
# If that returns exactly one then use it
... (where {XXX} is the placeholder for the user supplied search term).
The idea here is that I first try a precise match, then I try it under the assumption that the term already may contain SQL wildcards, then I try suffixing the % wild card and finally I try wrapping it with % wild cards.
At any point if I've found an unambiguous match then I use it. If I find more than one match at any point (not shown in the psuedo-code here) then I might throw an exception or I might return them or a subset of them based on the specifics of what I'm doing.
(In reality I'm using the parameter interpolation features of Python or Perl or sanitizing my inputs to allow wild cards while preventing SQL injections; so the code doesn't look like what I'm showing here. This is just to convey the general idea).
My goal is to allow my scripts to be called with the minimum unambiguous arguments supplied which sounds roughly similar to what your clients are requesting here.
From a usability perspective most users will get the first characters of any input right. So exact match following by suffixed wildcard match is most likely to succeed most of the time. In my case my users are likely to be familiar with SQL wildcards and may prefer to use them to construct their own unambiguous match; and logically that attempt has to be inserted before I start suffixing or wrapping it with my own wildcards.
This is why I use this specific sequence of matching attempts.
I have a function that I use called sqlf(), it emulates prepared statements. For instance I can do things like:
$sql = sqlf("SELECT * FROM Users WHERE name= :1 AND email= :2",'Big "John"','bj#example.com') ;
For various reasons, I cannot use prepared statements, but I would like to emulate them. The problem that I run into is with queries like
$sql = sqlf("SELECT * FROM Users WHERE id IN (:1)",array(1,2,3) );
My code works, but it fails with empty arrays, e.g. the following throws a mysql error:
SELECT * FROM Users WHERE id IN ();
Does anyone have any suggestions? How should I translate and empty array into sql that can be injected into an IN clause? Substituting NULL will not work.
Null is the only value that you can guarantee is not in the set. How come it is not an option? Anything else can be seen as part of the potential set, they are all values.
I would say that passing an empty array as argument for an IN() clause is an error. You have control over the syntax of the query when calling this function, so you should also be responsible for the inputs. I suggest checking for emptiness of the argument before calling the function.
Is there a possibility that you could detect empty arrays withing sqlf and change the SQL to not have the IN clause?
Alteratively, you could postprocess the SQL before passing it to the "real" SQL executor so that "IN ()" sections are removed although you'd have to do all sorts of trickery to see what other elements had to be removed so that:
SELECT * FROM Users WHERE id IN ();
SELECT * FROM Users WHERE a = 7 AND id IN ();
SELECT * FROM Users WHERE id IN () OR a = 9;
would become:
SELECT * FROM Users;
SELECT * FROM Users WHERE a = 7;
SELECT * FROM Users WHERE a = 9;
That could get tricky depending on the complexity of your SQL - you'd basically need a full SQL language interpreter.
If your prepare-like function simply replaces :1 with the equivalent argument, you might try having your query contain something like (':1'), so that if :1 is empty, it resolves to (''), which will not cause a parse error (however it may cause undesirable behavior, if that field can have blank values -- although if it's an int, this isn't a problem). It's not a very clean solution, however, and you're better off detecting whether the array is empty and simply using an alternate version of the query that lacks the "IN (:1)" component. (If that's the only logic in the WHERE clause, then presumably you don't want to select everything, so you would simply not execute the query.)
I would use zero, assuming your "id" column is a pseudokey that is assigned numbers automatically.
As far as I know, automatic key generators in most brands of database begin at 1. This is a convention, not a requirement (auto-numbered fields are not defined in standard SQL). But this convention is common enough that you can probably rely on it.
Since zero probably never appears in your "id" column, you can use this value in the IN() predicate when your input array is empty, and it'll never match.
The only way I can think to do it would be to make your sqlf() function scan to see if a particular substitution comes soon after an "IN (" and then if the passed variable is an empty array, put in something which you know for certain won't be in that column: "m,znmzcb~~1", for example. It's a hack, for sure but it would work.
If you wanted to take it even further, could you change your function so that there are different types of substitutions? It looks like your function scans for a colon followed by a number. Why not add another type, like an # followed by a number, which will be smart to empty arrays (this saves you from having to scan and guess if the variable is supposed to be an array).