I'm trying to redirect all incoming requests to /index.php (except requests starting with ? like /?foo=bar)
ModRewrite could certainly solve this problem easily, but are there any other solutions?
For example I was thinking about creating a manual 404 page (in PHP) that would redirect to /index.php manually, but I'm not sure if/how this would work.
It would also be important to have the information from the original URI in index.php, e.g. when somebody is requesting domain.com/search-term then I need that information ("search-term") in index.php.
Interesting question. Even frameworks such as laravel will require a RewriteRule to push requests to index.php before doing any routing from within the framework itself.
I feel like to do a catch all as you are suggesting there would need to be some amount of Apache configuration changes.
your suggestion of redirecting the 404 page to index.php would work but the SEO implications id assume would be horrible. Any links to your site to any page other than index.php would give a 404 Not Found error in the HTTP headers (even though it shows index.php).
but.. with all that said, if you still want to do it that way, heres how you'd do it:
in .htaccess
ErrorDocument 404 /index.php
this will make your 404 not found page index.php
your redirect variables will be in the $_SERVER array and will be prefixed with REDIRECT_
print_r($_SERVER); from a redirect gives me (i removed any key value pairs without REDIRECT_ at the beginning):
Array
(
[REDIRECT_REQUEST_METHOD] => GET
[REDIRECT_STATUS] => 404
[REDIRECT_URL] => /blsah.html
)
so REDIRECT_URL would be what you would use to get "search-term" from domain.com/search-term
you can find a more complete list of the possible redirect variables here:
http://httpd.apache.org/docs/2.2/custom-error.html
You need to use some sort of routing component, such as those that exist in frameworks to handle redirect all routes. For example if you were using laravel 4 you could do something like this within the routes.php file:
Route::any('/', function(){
//Do Magic Stuff
});
Route::any('{all}', function($uri)
{
//Check query string here - redirect as necessary
if (stripos($_SERVER['QUERY_STRING'], '?') !== false)
//Redirect or do stuff depending on your use case
else
Redirect::to('/'); //Otherwise redirect to your homepage
})->where('all', '.*');
The all will match all routes and redirect them to the first route which would be your default. There are plenty of php frameworks out there that you could probably do this with or could even do it from scratch - this is just one framework that I find to be great to work with.
Credit to Jason Lewis: Get all routes, Laravel 4
Laravel Routing: http://laravel.com/docs/routing
Related
We currently have a full Angular project running in a sub-dir on our server and a physical "device" using a hardcoded URL to send a user to that page.
I'm looking for some kind of way to "intercept" the request via a PHP script first to (for example, not the real purpose) see if the requested "ID" param for that browser page has enabled the option to view the browser page or if it has been configured by the user to return a 406 HTTP response (for example).
Currently:
- ..com/app/routing-view?id=1234 => Angular view -> fetch info
Idea:
- ..com/app/routing-view?id=1234 => PHP-script -> isValid => forward to angular and do a normal 'webview' -> fetch info
- ..com/app/routing-view?id=2889 => PHP-script -> notValid => HTTP code
I thought about having a .htaccess "intercept" the url and forward it to a .php file. Do the magic and checks there, and then forward the browser to the original url, but to "bypass" the previous interceptor.
It's about that last part that I'm currently having issues. Because it's Angular and it is using paths, I can't just say "okay, redirect to index.html instead of index.php" because it would need to be something like ..com/app/routing-view?id=1234 (and the index.html is located in the /app directory.
I don't want to add PHP code to the original Angular-index file if that could be avoided.
Am I looking at this right or would there be a different, more efficient way to tackle this?
The reason for all this is that I want to (for example) return a different HTTP code or different headers to the device instead of a 200 html header response even if the ID turned out to be disabled or something like that.
Got it to work via a simple .htaccess, a parameter and an "interceptor" script. Quite simple and basic really, not sure why my brain didn't go this route before posting my question.
Added the .htaccess to the root of the Angular application with the following code.
RewriteEngine On
# Check if the request has been intercepted before (via URL parameter)
RewriteCond %{QUERY_STRING} !(^|&)intercepted=true
# .. If not, rewrite the page to use the interceptor script (only if it matches the route).
RewriteRule ^my-route dir-of-script/extra/interceptor.php?url=https://%{HTTP_HOST}%{REQUEST_URI}?%{QUERY_STRING} [L,QSA]
# Other stuff for rewriting the Angular routes etc
...
Added a /dir-of-script/extra/interceptor.php like-script that parses the URL from the GET parameter, fetches the info, does the checks and depending on the result, returns the output or redirects the page and let it through.
This adds a ..&intercepted=true parameter to the original URL so that the .htaccess doesn't intercept it again.
This seems to be working like a charm (for my situation). The only "downside" is that this counts as a redirect and not just a rewrite when it was allowed to go through. Will look further into it, to maybe let the PHP script "serve" the Angular content instead of redirecting to it.
I'm writing a small php site and I'm trying to structure it properly so that requests are handled centrally and there is a single point of entry to the code.
So I'm using the guide for a single entry point described here: https://thomashunter.name/blog/php-navigation-system-using-single-entry-point/
The mod_rewrite rule works well until you request a directory that actually exists on the server. I've disabled directory indexes but now the accesses behave differently depending on whether there is a trailing slash in the URL or not. With a slash, everything behaves the way I'd like (URL bar is www.example.com/images/ and the server returns a 404 created by my php script) but without a trailing slash the URL is rewritten to www.example.com/index.php?s=images which looks messy and exposes too much information about the structure of my site.
Seeing how it works with a trailing slash, ideally I want it to work the same way without the trailing slash. Otherwise, if it didn't work in any case, I'd settle for a simple redirect, although I don't like the idea of highlighting the real directories.
My .htaccess looks like this:
RewriteEngine On
RewriteRule ^([a-zA-Z0-9_]+)/?$ index.php?s=$1 [QSA]
Options -Indexes
ErrorDocument 403 index.php
I've also put in a header redirect but the ?s=images still gets appended to the URL (I am aware this can be written better but I'm experimenting with various combinations at the moment):
if (startsWith($_SERVER['REQUEST_URI'], "/main"))
{
header('Location: '.'/');
exit;
}
else if (startsWith($_SERVER['REQUEST_URI'], "/images"))
{
header('Location: '.'/');
exit;
}
where the definition of startsWith is (taken from this StackOverflow answer):
function startsWith($haystack, $needle)
{
return $needle === "" || strpos($haystack, $needle) === 0;
}
Finally, I'm looking for a solution that doesn't require copying dummy index.phps into every directory as that can get difficult to maintain. Any help or guidance will be appreciated.
you want some sort of routing, either via only apache Routing URLs in PHP or via one of the libraries (apache+php) that are avaliable
(like this one http://www.slimframework.com/)
.htacesss
RewriteCond %{REQUEST_URI} ^/api/(.+)$
RewriteRule ^api/(.+)$ /index.php?api=%1 [QSA,L]
example ajax url request:
'http://hostname.com/api/ext/list.php?query=de'
I want to be able to redirect urls in this format to the following
index.php?api={requested_filename}¶m1=value1¶m2=value2 ...
because the whole site is processed through a bootstrap process in index.php which has a routing part loading configs, templates etc...
When I try a jquery code for example, the POST data is lost after redirect.
$.ajax({
url: '/api/contact.php',
type: 'POST',
data: {
email: $("#contactEmail").val(),
name: $("#contactName").val(),
message: $("#contactMessage").val()
// etc ...
}
});
I've read that you cannot preserve data on a http redirect. But how do all the frameworks avoid that? I've coded in many, and every one is bootstraped through the index.php and there are rewrite rules in the .htaccess file for enabling pretty urls. So in Yii for example, I would call an url "api/uploads/latests.json" with some POST data and the controllers on the backend would receive that data. What am i missing here?
note: I've tested the [P] mod_rewrite parameter, and i think that this server doesn't have mod_proxy enabled.
There is a difference between a rewrite and a redirect.
Rewrite is an apache (and other servers) module that will follow a set of cond/rules to map a requested url to files on the server (ex: a bootstrap rewrites all urls to a single file, usually index.php. A mvc might map /model/controller/view uri to an index.php that calls the appropriate mvc files).
A redirect actually changes the page you are on. Someone requests page A.php and that page says "what you are looking for is on B.php" and so your browser goes to B.php.
A rewrite will preserve post parameters because the url doesn't change. A rewrite will just change the script being requested, but to the browser it looks like the page still exists at the requested url.
A redirect will not preserve post parameters because the server will redirect you to another page completely.
What it appears you are trying to do is a rewrite, not a redirect. You should have no problems getting the post parameters.
To fix this, how are you checking in index.php that there are no post parameters? Are you sure the controller you are expecting is getting called?
All POST data is lost on redirect. There is no way to preserve it via htaccess rewrite/redirect rules.
The redirect (all 301,302,303) received by the client (all major browsers I know) is treated as a new url to make a GET request to. Browsers won't automatically tack on old post parameters to this URL--even if the source of the redirect was a POST request.
The only way I've every found around this is to do the rewrite inside code and covert the POST parametes to GET parameters and stick them on the end of the new url. In php you then issue a header location change (or whatever redirect call your library of choice uses):
header("Location: http://www.example.com/?my_old_post_args=123");
exit;
for any one have this problem i have the sam problem and i use
some thing like this
RewriteRule ^services/MainService/(.*)$ http://193.9.162.91/mobile-feed/mobile.list.news.images.php?original_request=$1 [R=301,L]
this will not work with ajax post i have to chnage the RewriteRule to
RewriteRule ^services/MainService/(.*)$ http://193.9.162.91/mobile-feed/mobile.list.news.images.php?original_request=$1 [QSA,L]
this work
and in the php file i have
$inputJSON = file_get_contents('php://input');
$input= json_decode( $inputJSON, TRUE ); //convert JSON into array
print_r($input);
I'm trying to figure out how to set up a holding/"under maintenance" page in Zend Framework for when I am upgrading the database or something and don't want anyone using the site. I'd like to have a static HTML page and have all traffic redirected to that.
I'd rather not use .htaccess and would like to do it via the bootstrap file.
Any ideas?
Thanks.
I've set Apache to show index.html in preference to index.php (which bootstraps the ZF). As long as you don't link directly to /index.php anywhere, then you can just drop in an index.html file, and it will show that in preference to the ZF site.
An alternative is to have an entry in your configuration .ini file, and as soon as you have read the configuration:
if ($config->maintenance) {
readfile(APPLICATION . '/../public/maintenance.html');
exit;
}
You may want to add another check in there for a particular IP address (your own) as well, so that you can get though even when everyone else is blocked.
I've done this by creating a plugin that check the validity of the request each time that a page is requested.
During the execution of the plugin in the "preDispatch()" you can analyze a variable from the config that it will hold your current status as active/under maintenance and let the request flow to the original destination or redirect it to a landing page for this purpose.
Code sample
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
// get your user and your config
if( $config->suspended && $user->role()->name != "admin"){
$request
->setModuleName( 'default' )
->setControllerName( 'index' )
->setActionName( 'suspended' )
->setDispatched(true)
;
}
}
You could check your configuration file for a maintenance_mode switch and redirect every request from within the bootstrap to your static html maintenance page.
I have a blog post that demonstrates how to do this. Setting up a maintenance page with Zend Framework
I would use plugin with dispatchLoopShutdown() and based on the config settings i would redirect the request to any controller you want.
I followed all of these suggestions to a TEE on Zend 1.12. I googled around. Tried using application.ini, setting the plugin path, using zend_loader_autoloader_resource(), using Zend_Loader_PluginLoader. NONE of these worked for me. I ended up writing a .htaccess:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/maintenance\.php$
RewriteRule ^(.*)$ /maintenance.php [R=503,L]
This is why Zend is the worst framework. Tons of different options on how to do something simple, Official Documentation is extremely ambiguous and unclear, and nobody fully understands or can explain the correct way to do anything so I end up wasting an hour of my time trying to do things correctly.
In Zend framework, using the MVC, if A user surf explicitly to http://base/url/index.php instead of just http://base/url, The system thinks the real base url is http://base/url/index.php/ and according to that calculates all the URLs in the system.
So, if I have a controller XXX and action YYY The link will be
http://base/url/index.php/XXX/YYY which is of course wrong.
I am currently solving this by adding a line at index.php:
$_SERVER["REQUEST_URI"]=str_replace('index.php','',$_SERVER["REQUEST_URI"]);
I am wondering if there is a built-in way in ZF to solve this.
You can do it with ZF by using Zend_Controller_Router_Route_Static (phew!), example:
Read the manual page linked above, there are some pretty good examples to be found.
$route = new Zend_Controller_Router_Route_Static(
'index.php',
array('controller' => 'index', 'action' => 'index')
);
$router->addRoute('index', $route);
Can't say I totally disagree with your approach. That said, others may well point out 5000 or so disadvantages. Good luck with that.
Well it really depends on how you want to solve this. As you know the Zend Frameworks build on the front controller pattern, where each request that does not explicitly reference a file in the /public directory is redirected to index.php. So you could basically solve this in a number of ways:
Edit the .htaccess file (or server configuration directive) to rewrite the request to the desired request:
RewriteRule (.*index.php) /error/forbidden?req=$1 // Rewrite to the forbidden action of the error controller.
RewriteRule index.php /index // Rewrite the request to the main controller and action
Add a static route in your bootstrapper as suggested by karim79.
Use mod_rewrite. Something like this should do it:
RewriteRule ^index.php/(.*)$ /$1 [r=301,L]
I don't think you should use a route to do this.
It's kind of a generic problem which shouldn't be solved by this way.
You better should have to do it in your .htaccess, which will offer you a better & easier way to redirect the user to where you want, like to an error page, or to the index.
Here is the documentation page for the mod_rewrite
I've never faced this problem using Zend Framework. just do not link to index.php file. that's it. and when your are giving your application's address to users, just tell them to go to http://base/url/
when the user enters http://base/url/ her request URI is base/url and your .htaccess file routs the request to index.php, but the request IS base/url. you do not need to remove 'index.php' from the request. because it is not there.
when you are trying to generate URLs for links and forms and ..., use the built-in url() view helper to generate your links. like this:
// in some view script
<a href="<?php
echo $this->url( array('controller'=>'targetController','action'=>'targetAction') );
?>" >click</a>
do not worry about the link. Zend will generate a URL for you.
The way I look at this is that if I have a website powered by PHP and a user goes to http://site/index.aspx then I would send a 404.
Even though index.php does exist in theory, it's not a valid URL in my application so I would send a 404 in this case too.