2

PHP:

$category = $_GET["category"];
$result = "SELECT * FROM my".$category." ORDER BY id_".$category.";

htaccess:

RewriteRule ^category_(.*)\/?$ site/category.php?category=$1 [NC,L]
RewriteRule ^category_(.*)_(.*)\/?$ site/category.php?category=$1&page=$2 [NC,L]

If I insert in url browser:

 site.com/category_namecategory

It works

But if I insert:

site.com/category_namecategory_numberpage

Return:

Error: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'myDB.my_2' doesn't exist

2 is number page, but I want the category not the number.

I do not know where I am going wrong

Gislef
  • 1,555
  • 3
  • 14
  • 37

2 Answers2

2

Your first rule matches both requests, you can fix this by adding a negated character class in your first Rewrite pattern.

    RewriteRule ^category_([^_]+)/?$ site/category.php?category=$1 [NC,L]
RewriteRule ^category_(.*)_(.*)/?$ site/category.php?category=$1&page=$2 [NC,L]
Amit Verma
  • 40,709
  • 21
  • 93
  • 115
  • 1
    Thank you @starkeen your logic is functional. This also works, but I followed the recommendation of chris85 for to avoid sql injection – Gislef Feb 29 '16 at 02:33
  • 2
    Just so you don't make any false assumptions; The SQL injection danger lies here: `$result ="SELECT * FROM my".$category." ORDER BY id_".$category.";`. http://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php – ippi Feb 29 '16 at 03:04
2

Your first rule with .* and an optional / is not strict enough and is matching for both URLs.

This updated rule should allow for the URLs you are expecting. The [] is a character class if there are more characters you need to allow add them in there. The {} is a range, first number is minimum, second maximum.

RewriteRule ^category_([a-zA-Z]{4,20})/?$ site/category.php?category=$1 [NC,L]
RewriteRule ^category_(.*)_(.*)/?$ site/category.php?category=$1&page=$2 [NC,L]

A good place to test regex's is regex101. It shows what the regex is matching and explains each part of it.

Original example: https://regex101.com/r/zO7lI8/1
New example: https://regex101.com/r/zO7lI8/2

That should resolve your .htaccess issue.

Note on regex101 the delimiter is / so all /s need to be escaped, depending on the language/software the regex is being used a delimiter may not be needed. The / is not a special character unless it is the delimiter. So it doesn't need to be escaped.

This:

$category = $_GET["category"];
$result = "SELECT * FROM my".$category." ORDER BY id_".$category.";

Is still open to a sql injection though. A user could input anything into $_GET["category"] and get contents from your database. A malicious user could possibly even pull all usernames, passwords, and emails.

Take a look at:

How can I prevent SQL injection in PHP?
http://php.net/manual/en/security.database.sql-injection.php
https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet

for more information on SQL injections and how to prevent them.

Community
  • 1
  • 1
chris85
  • 23,846
  • 7
  • 34
  • 51
  • Again thank you @chris85 The real name of my table in my database is something like `Mytablename_secondname_thirdname` I put only one part of the table name in a variable. This is still a problem? – Gislef Feb 29 '16 at 03:22
  • You should make a whitelist of terms that can be passed in, an array, and check that the provided value at least is in that array. Otherwise users can do whatever they want with your db. – chris85 Feb 29 '16 at 03:24
  • I´m using PDO example for values of table `$stmt->bindparam(":title",$titless); $stmt->bindparam(":content",$contentss);` This no longer dispenses create whitelist array? – Gislef Feb 29 '16 at 03:32
  • You can't bind tables/columns. Here's a rough idea of the whitelisting approach, http://stackoverflow.com/a/8255054/4333555. – chris85 Feb 29 '16 at 03:33
  • Okay. But first the .htaccess I followed your tip and put to accept letters `[a-zA-Z]{4,20}`, anything that has typed characters directs to notfound.html. So I can not imagine how it will be possible SQL injection attack url – Gislef Feb 29 '16 at 03:44
  • Second rule has no limits and is used the same way, no? Also if a user figured out domain structure loading `site/category.php?category=whateveriwant` would still work. The PHP should always have safeguards in place. – chris85 Feb 29 '16 at 03:48
  • second rule: ([a-zA-Z]{4,20})_([0-9]{1,200}) – Gislef Feb 29 '16 at 03:50
  • Oh, okay, hadn't seen that you updated that. Okay, still if user finds real URL it will bypass. It is always best to have the script follow best practices than to expect how a user will get to the page. If they obtain real path could still inject.. – chris85 Feb 29 '16 at 03:53
  • You have an example of how to avoid access the actual path the url? – Gislef Feb 29 '16 at 04:06
  • I don't have an example of that. I wouldn't take that approach though either. – chris85 Feb 29 '16 at 04:18
  • thank you @chris85. One last question, how to accept only letters and `_`? I'm not finding the site http://regexr.com/ – Gislef Feb 29 '16 at 04:28
  • Just added it inside the character class, try out the regex101 links. – chris85 Feb 29 '16 at 04:45
  • Also `{1,200}` is not `1-200` that is `0` through `200` possible additional numbers. Regexs don't know values just patterns. You could trick it with a longer pattern, or just do `\d{1,3}` which would allow `0-999`. – chris85 Feb 29 '16 at 13:07
  • Now I understand, to `1-200` I put `1,3`. Thank you – Gislef Feb 29 '16 at 18:23