How to create dynamic webpage with custom name? - php

I have looked around and attempted my own research on this topic but to no avail just yet.
I have a dynamic webpage set up to look for a ID from a database to retrieve elements required. This results in of course the web page looking like www.site.com/page?id=1
My desired outcome would be like a title for this page to be called.
Such as say I had a fruit product it and user went to my site and went to the address /fruit it would it would be the content of ?id=1 just as an example.
I have seen this used on many a site but not sure how this is programmed or works. Is this something to do with a htaccess document?
Thanks in advance. Appreciate all the help.

While this has been asked and answered many times, I know many people find it difficult to search for this since there are so many common "noise" words related to it. For that reason, I believe it's worth answering again.
If you're using Apache as your webserver (which I'm assuming you are since you mention .htaccess), what you're looking for to create those "clean URLs" is mod_rewrite, which takes a set of rules and rewrites the URL requested by the browser to another path or script.
You would typically enable this in your Apache config or in .htaccess, and in a simple form (a one-to-one mapping) at it would look something like this (provided mod_rewrite is installed):
RewriteEngine On
RewriteRule ^fruit$ index.php?type=1 [L]
Now obviously that doesn't scale well if you have a bunch of dynamic pages you want to create, so what you can do is tell all pages that aren't a really file or directory to be passed to a file for processing, like so:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L]
In this case we're rewriting any request that doesn't resolve to a real file or directory to index.php, and then using the "last" flag [L] to stop processing other rules. Then in our PHP script, we can access the virtual path (in this case /fruit) by using $_SERVER['PATH_INFO'] and doing whatever conditional logic we want with that. If you don't get anything in that variable, ensure that the AcceptPathInfo On directive is set in your Apache config or .htaccess.
A way to test the basic concept/logic without having any rewrite rules would be to use a URL like https://example.com/index.php/fruit. You'll then see that in index.php $_SERVER['PATH_INFO'] will contain the string /fruit. You can rewrite URLs to files in other directories, chain rewrite rules, redirect the browser to other URLs, or even edit environment variables.
There are many good tutorials around using mod_rewrite for clean URLs, so I won't attempt to cover all the nuances here. Just know that it's a very powerful tool, but it's also pretty easy to break your rules if you aren't very comfortable with regular expressions or get lost in the many rules that are commonly in a configuration.
Note that if this is an existing site, you'll also want to use mod_rewrite or mod_redirect to redirect the old URLs to the new ones so they don't break (and for the benefit of having a single URL for search rankings).

Related

How to clean a url with php without using htaccess?

I have a problem with a project I'm doing with PHP and it's in the URLs.
When I load a script like index.php everything works fine, the problem is when I load a script that is located within two or more directories.
In the URL the scripts with the routes begin to be enmeshed
Here is an example of the problem I have
I need to load a script, even if it is in several levels of nesting, make its functionality and in the url is reflected as:
I need to have something like this
1:
I thank you in advance.
Regards
You can't use PHP to achieve this. PHP is not responsible for determining if PHP (let along a particular PHP script) will handle any given URL.
You have to configure your webserver to do it. Since you mention .htaccess but provide no further information about your server, I'm going to assume you are using Apache HTTPD.
For Apache, that means using mod_rewrite, Alias or something similar. You can put the configuration for those tools in .htaccess, but you don't want to and the documentation advises not to use them.
So put your mod_rewrite or Alias configuration in the main Apache configuration.
You're going to need an htaccess rule no matter what. However, it doesn't have to be a mod_rewrite rule. The reason you need this rule is because PHP is not responsible for the routing - it is merely responsible for the execution of your script.
The point of the rule is to direct apache and instruct it to execute the right script (in your case, script32.php) while keeping the request uri as intact as possible.
There are two ways around it, basically.
Way 1 (cleaner): mod_rewrite
This is pretty straightforward, the set of rules you need are as follows:
# If the requested file name is a valid file/inode
RewriteCond %{REQUEST_FILENAME} -f [OR]
# ...or a directory
RewriteCond %{REQUEST_FILENAME} -d
# ...then throw them straight on it
RewriteRule (.*) - [L]
# ...otherwise, redirect to script32.php with the full content of the request in query string
RewriteRule (.*) /welcome/script32.php?$1 [L]
The requested URL is now in $_SERVER['QUERY_STRING'] and you can now do whatever you like with it in PHP
Way 2: catchall
This does not rely on mod_rewrite and may therefore be slightly faster. However, technically, it's a cheap hack. The way around it is as follows:
ErrorDocument 404 /welcome/script32.php
The requested URL can now be found in $_SERVER['REQUEST_URI'] and is available for parsing in PHP. However, with this, you've also disabled "legit" 404 errors from being generated through apache - and should make sure to obey proper behaviour in PHP to compensate.

Rewriting url parameters using rewritemap and mysql

I realize this question has been beaten to death by a lot of people asking it, but most of the answers appear to be for a very specific case that only suits their needs, and so far I have not found a suitable solution (at least, as far as i can see).
My problem is that I am trying to make my website redirect URL parameters from an ID to an actual string.
For example:
www.example.com/?category=1
would display as:
www.example.com/software
while
www.example.com/?category=2
would be displayed as:
www.example.com/software/desktop
From what I've read up, I'm supposed to be looking into an apache rewritemap, and this is where my confusion comes in. I'd really rather not have to load from a flat txt file, as I'd like to make this as dynamic as possible, and I have read that I can make it read from a php file and read it from a MySQL database, which is what I'd like.
The problem with that is that I'm really not too sure what the proper way is of achieving this. The RewriteMap document only somewhat covers flat .txt files, and not achieving it with MySQL.
So basically what I'm asking is if someone can explain how to achieve what I'm looking for, or at least point me in the right direction. Most of the threads I've found so far have sadly not been too helpful as of yet, but it's possible I might have passed by useful ones.
If it helps, right now, my MySQL data is formatted in an inherited structure like so:
ID | Title | Link | Parent
1 | Software | /Software/ | NULL
2 | Desktop Software | /Software/Desktop/ | 1
2 | Mobile Software | /Software/Mobile/ | 2
PS:
I should add that most solutions I've found give this as the example:
RewriteMap examplemap prg:/path/to/file.php
RewriteRule (.*) ${examplemap:$1}
Yet it never gives information as to what is in that file.php, and how it queries and returns the value.
EDIT
I should mention that I am on a shared hosting server, not my own private one, and so I may not have access to all possible options
EDIT 2
Just for the sake of clarity:
What I'm trying to do is make it so that a user who accesses 'example.com/software' would be treated as though they are on 'example.com/?category=1'; basically prettying the link and making it more readable. The only thing is, I'm trying to read it from a database
If you don't have access to the server or vhost config, you can't use RewriteMap anyways. The map itself needs to be defined in either the server or vhost config, not in an htaccess file. But apache 2.4 has an option of using mod_dbd to use an SQL query to define a rewrite map.
If you need to access MySQL, you're probably better off doing all of this in PHP instead of using mod_rewrite. You'd use mod_rewrite to route to your php file, which would then redirect. Maybe something like this?
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /file.php?link=$1 [L]
So when someone requests http://example.com/Software/Mobile/, the request gets rewritten to: /file.php?link=Software/Mobile/, and your file.php script would do the lookup.
Or if you actually mean the other way around:
RewriteCond %{QUERY_STRING} category=([0-9]+)
RewriteRule ^$ /file.php?ID=%1 [L]
So when someone requests http://example.com/?category=2, the request gets rewritten to: /file.php?ID=2 and the php script does the lookup.
My suggestion would be to look at utilizing a front controller pattern. I think that once you start getting into user friendly URL's or the concept of "routes", that the front controller can really simply things since you no longer have to worry about mapping specific URL's to specific controllers at the web server level.
If you have Apache mod_dir enabled (chances are you do), you could do something like this in your Apache config or .htaccess:
FallbackResource /index.php
This simple directive will direct any requests that would otherwise cause a 404 error to be directed to a front controller at /index.php.
This can also be done via mod_rewrite like this:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php [L,QSA]
In the front controller, you could evaluate the URI and route the request to whatever logic need to handle the request. You could do this via lookup of routes from a database or a hard-coded array of routes or whatever. (I would suggest however that, if using a database, you have a cached version of the routes available for quick access).
There are a number of different PHP route controllers available such that you don't need to reinvent the wheel (most every modern framework has some sort of routing concept).

How to setup .htaccess to show 404 for unallowed urls?

I noticed in Drupal if you add .php to the url bar of any page it gives you a 404 message; clean urls enabled. The page is obviously a .php, but the .htaccess is preventing the user from being able to tamper with url extensions in the url bar. How could you do this using .htaccess. I have file extensions omitted at the moment, but would also like to add that feature. Thank you.
Also, this question does not pertain to Drupal. I only mentioned Drupal for and example.
Just because a file contains PHP code it doesn't mean it has to have the .php extension; even more so when you're accessing a file over the internet.
When you request http://mysite.com/page and you're using an .htaccess like Drupal's, the request is forwarded onto index.php?q=page whereupon Drupal will check it's database for a path matching page. If it finds one it will display the content for that page, if not it will (rightly) give a 404.
If you want all of your pages to be accessible with a PHP extension you could add an extra rule in your .htaccess file to remove .php from any request where the PHP file doesn't physically exist:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\.php $1 [NC]
Bear in mind though that this adds zero extra value for your site's visitors (in fact they have to remember a file extension as well as the path to the page), and it exposes exactly what server-side technology you're using so a potential attacker would have some of his work done for him.
Hope that helps.
Could you please explain that in more depth. How can it redirect content into an existing page? Is that common practice / typical way of doing things?
Yes it is a very common practice, used by most frameworks and CMS.
The principle is simple: you setup your .htaccess so that every request which doesn't match a real file or directory will be redirected to a front controller, usually the index.php in the root directory of the application. That front controller handles the request by analyzing the URL and calling the necessary actions.
In this way you can minimize the rewrite rules to just one, and you can offer customized 404 pages.
I dunno Drupal but in the usual php app every request being routed to the front controller which performs some validations and throws 404 on errors.
easy-peasy

PHP: Best solution for links breaking in a mod_rewrite app

I'm using mod rewrite to redirect all requests targeting non-existent files/directories to index.php?url=*
This is surely the most common thing you do with mod_rewrite yet I have a problem:
Naturally, if the page url is "mydomain.com/blog/view/1", the browser will look for images, stylesheets and relative links in the "virtual" directory "mydomain.com/blog/view/".
Problem 1:
Is using the base tag the best solution? I see that none of the PHP frameworks out there use the base tag, though.
I'm currently having a regex replace all the relative links to point to the right path before output. Is that "okay"?
Problem 2:
It is possible that the server doesn't support mod_rewrite. However, all public files like images, stylesheets and the requests collector index.php are located in the directory /myapp/public. Normally mod_rewrite points all request to /public so it seems as if public was actually the root directory too all users.
However if there is no mod_rewrite, I then have to point the users to /public from the root directory with a header() call. That means, however that all links are broken again because suddenly all images, etc. have to be called via /public/myimage.jpg
Additional info: When there is no mod_rewrite the above request would look like this: mydomain.com/public/index.php/blog/view/1
What would be the best solutions for both problems?
Edit/Additional question:
Is there a way to make /public/ the base dir using plain htaccess code?
Write the app in such a way that it doesn't need mod_rewrite to function (at the cost of having "ugly" urls). Progressively enhance it with mod_rewrite to achieve the desired result. This probably means that you'll need to store some base path config info in your app.
I don't understand these problems at all.
Yes, this is surely the most common thing you do with mod_rewrite, yet with 2 conditions:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
So, nothing hurt your existing images.
Why not to use just absolute path, e.g. /myapp/public/myimage.jpg, so, no virtual directory will hurt image path?
what about path info? You could use it without mod_rewrite
/index.php/path/to/another/file.jpg
<?php
echo $_SERVER["PATH_INFO"]; // outputs /path/to/another/file.jpg
?>
Anyways, if you want to know if mod_rewrite is supported by your server :
<?php
echo "mod_rewrite : ".(!empty($_SERVER["REDIRECT_URL"])?"supported":"not supported");
?>
Then you ll know if mod_rewrite is the solution or maybe path_info is more well suited for you, you could make support functions that could look for both too.

validating .htaccess before deployment

In order to get better SEO and cleaner URLs, I tend to export certain RewriteRules directly into the .htaccess (eg, RewriteRule ^The_North_Face(.*)$ index.php?a=brands&id=27&extras=%1 [NC,L] and so forth for each brand or category). It's a lot more complex than that but today I discovered that the file is only as good as the data it's trying to use. The site owner managed to put empty category names / URLs and some unescaped characters that caused a nasty internal server error, blocking any and all site access (inclusive of the tool to rebuild it).
I realise that the best defence here will probably be good training + failsafe at the CMS level. Regretfully, this is a 3-rd party solution called CubeCart which I can't dip into for the time being, the SEO solution was supposed to be standalone and just using the CubeCart data.
Obviously, I'd have to add some checks to do with brand / category / landing page names. Even so, I'd very much like to parse / validate the newly built .htaccess before replacing the 'live' one in order to avoid possible issues to do with syntax. Are there any syntax validators / ways to test Apache against a new .htaccess?
I can also think of deploying it in a sub-directory, then using curl to GET a few requests as a test, anything else I can do?
You may use something like WordPress does:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
... and then in the index.php file parse the $_SERVER["REDIRECT_URL"] against your website's URI logic. This way it would be easier for you to process any database variables like brand or category automatic through the PHP, without editing the .htaccess file on every content change.
I would suggest redirecting all requests to a file rewrite.php. There, you parse the requested file and match it against an array of rules. You use the result for filling the $_GET array and then include the correct file.
PHP syntax errors are much easier to find and you will definitely not get a 500 error page.

Categories