Silex: reset the root route when the app is not at the webroot level - .htaccess

I am playing with Silex, trying to use it as a RESTful json api at a shared web hosting. The host has Apache web server. I would like the Silex app to sit in the folder which I tentatively called experiments/api, so the app becomes at a different level than the webroot. As per the documentation, the .htaccess file that I placed in the Silex app folder looks like this:
RewriteEngine On
RewriteBase /experiments/api
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ src/index.php [QSA,L]
(meaning that the app sits in the /experiments/api folder, and the main controller file is in src folder and is called index.php)
This gets the job done (i.e. the requests to /experiments/api/ are picked up by the Silex app), but the inconvenience is that the app now sees this /experiments/api/ prefix of the pathname.
For example. When I send a GET request to /experiments/api/hello I want the app to ignore the /experiments/api part, and to match only the /hello route. But currently the app tries to match this whole /experiments/api/hello path.
Is there a way to reset the root route for Silex to include the constant part of the path? I looked through the docs, but couldn’t find the answer.

You could use the mount feature.
Here's a quick and dirty example:
<?php
// when you define your controllers, instead of using the $app instance
// use an instance of a controllers_factory service
$app_routes = $app['controllers_factory'];
$app_routes->get('/', function(Application $app) {
return "this is the homepage";
})
->bind('home');
$app_routes->get('/somewhere/{someparameter}', function($someparameter) use ($app) {
return "this is /somewhere/" . $someparameter;
})
->bind('somewhere');
// notice the lack of / at the end of /experiments/api
$app->mount('/experiments/api', $app_routes);
//...

Related

How to remove public? from url in php project

I am currently working to build a small php mvc framework. in a framework i have a this folder structure.
-app
--controllers
-Post.php
-core
-logs
-public
--.htaccess
-- index.php
-vendor
in here index.php is working as Front Controller
in post controller is look like this..
<?php
/**
* Posts controller
*
*/
class Posts
{
public function index()
{
echo 'Hello index';
}
public function addNew()
{
echo 'Hello addNew';
}
}
in url, i want to remove project/public/?posts/index public/?. When i remove (public/?) and visit the url. its showing me this error message.
project/posts/index
The requested URL was not found on this server.
using public/? project/public/?posts/index is working fine. and its echo index message
project/public/
The .htaccess inside of the public folder contains:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
in project main root folder ...
i did't added .htaccess and index.php file.
in .htaccess when i add this line. url redirect to xammp welcome screen
RewriteRule ^(.*)$ index.php?$1 [L,QSA]
I'd say you want to internally rewrite all incoming requests to the controller inside the /project/public folder. But that is not what you do. The rule you implemented (RewriteRule ^(.*)$ index.php?$1 [L,QSA]) only rewrites relative to the requested folder. No mentioning of "public" in there.
The actual setup you need depends a bit on your http host setup here. Where its DOCUMENT_ROOT points to. Most likely to the folder that contains the file system structure you posted in your question. If so you should implement a rule that rewrites all incoming requests to the /project/public folder.
Something like that, though you probably need to tweak it to match your actual setup:
RewriteEngine on
RewriteRule ^ /public/index.php?%{REQUEST_URI} [L,QSA]
You can implement such rule in the http server's host configuration. Or, if you do not have access to that, you can use a distributed configuration file (if you have enabled those for the http host), so a ".htaccess" style file. That file should be located inside the folder your http hosts DOCUMENT_ROOT setting points to. So the folder containing the file system structure your posted.
Other setups are possible, this is just one option. The point is: you need to rewrite the requests to your controller. Where the controller actually is.

Server side includes as a templating/layout technique

I'm making a website for a company, and I wanted to use something like ASP.NET MVC layout pages to dynamically load the content into the layout, but the hosting provider used by the company doesn't support ASP.NET. I assumed they supported Node.js, because they said the only thing they didn't support was .NET, so I used a templating library called Embedded JavaScript Templates (http://ejs.co/) with Express.js, but then found out the hosting provider doesn't support Node, either.
Server side includes are definitely supported, but my question is can I use them to take the filename from the url where the user navigated, pass that into the server side include in the index.html page (the page I'm trying to use as the layout page) and have the web server inject the content where the include tag is? So far all the examples I've seen for server side includes show the file name entered as a literal, such as:
<!--#include virtual="physicians.html" -->
Whereas I want the file included to be determined by what the user entered when they navigated to the site. If it was http://website.com/physicians.html, then the index.html file should be loaded with "physicians.html" injected where the include was. Something like this (which obviously doesn't work):
<!--#include virtual="${REQUEST_URI}" -->
I also tried adding the following to the .htaccess file (note I am aware it doesn't enable server-side includes. I did enable SSI later and SSI was working, though not in the way I wanted it to as mentioned before):
<ifModule mod_rewrite.c>
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.html
</ifModule>
This came from http://krasimirtsonev.com/blog/article/deep-dive-into-client-side-routing-navigo-pushstate-hash. I used the above .htaccess configuration with his client-side library Navigo and some AJAX. Here's the JavaScript for loading content into the index.html file (/views is where the partial views are stored):
function loadViewContent(viewPath)
{
$('#main-content').load(viewPath, navSetActive);
}
var root = "http://www.caduceuscorporation.com";
var router = new Navigo(root);
router.on({
'/': loadViewContent.bind(this, "views/home.html"),
'index.html': loadViewContent.bind(this, "views/home.html"),
'/:page': function(params) {
loadViewContent("views/" + params.page + ".html");
}
})
.resolve();
It works great, except if I enter an invalid filename then it goes into an endless loop of loading index.html within itself. What the .htaccess configuration is doing is if the path is invalid, the server sends back the content for index.html, hence the infinite loop of index.html loading itself within itself.
Is there a way to use server-side includes to load content based on the URL the user entered, rather than a predetermined file? Or is there a different .htaccess configuration I need to use? I hope I have made it clear what I am trying to do. If SSI or a different .htaccess configuration doesn't work, I guess I'll have to use PHP maybe. I know the hosting provider supports that for certain.
I found a solution that works almost exactly like ASP.NET MVC layout pages, which is basically what I was asking for in my original question, but uses server-side includes (SSI) instead. I first had to figure out the right syntax for entering the variable name into the virtual parameter of the include tag. In my case, it should look like this:
<!--#include virtual="views${REQUEST_URI}.html" -->
And it should be entered into the "layout page" (in my case, index.html) where you want the "partial view" page to appear. So if I enter an address like https://example.com/physician, the server will translate "physician" to "views/physician.html" as the local relative path (since the views directory in my local web root is where my views are stored) and the content of that file will be inserted into index.html where the include tag is.
There's one more step. I modified my .htaccess file to look like this:
<ifModule mod_rewrite.c>
RewriteEngine on
Options +Includes
AddHandler server-parsed .html
IndexIgnore */*
RewriteCond %{DOCUMENT_ROOT}/views%{REQUEST_URI}.html -f
RewriteRule .* index.html
RewriteRule ^/$ index.html
</ifModule>
RewriteCond with the -f flag tells the server that if there is a file in the path listed after RewriteCond, then apply the RewriteRule following the RewriteCond. The DOCUMENT_ROOT after RewriteCond is necessary, because when using -f, relative paths don't work.
RewriteRules return a page based on the path the user entered into her browser. They take a regular expression matching the path the user entered. The first RewriteRule has the regular expression .*, which matches any path the user entered. But the RewriteCond before it tells the RewriteRule to only be applied when the file in the path the user entered exists in the views folder on the server. If not, the first RewriteRule is not applied. Otherwise, the server will send back index.html with the include tag replaced by the page the user entered, as described above. The final RewriteRule only matches /, otherwise there would be no way to go to the website root.
I actually put some conditional tags into my index.html file surrounding the include tag:
<!--#if expr="${REQUEST_URI} != '/'" -->
<!--#include virtual="views${REQUEST_URI}.html" -->
<!--#else -->
<!--#include virtual="views/home.html" -->
<!--#endif -->
This way, the home page can be loaded when the user goes to the website root, or otherwise the user couldn't access the home page without entering /home.
Resources I used:
https://httpd.apache.org/docs/trunk/howto/ssi.html (Apache SSI Tutorial)
RewriteRule htaccess if a file exists (Stack Overflow post)

Handling url rewrites and static files with Kraken JS

I have a one page app which I'm converting from a more traditional Apache setup to KrakenJS. It all goes really well except for one bit.
The app uses sockets to change its state, and we used to generate friendly URLs for our users to get back to a previous search. Using a .htaccess setup like so :
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(favicon\.ico|favicon\.png|media|robots\.txt|crossdomain\.xml|css|js)
RewriteRule ^(.*)$ index.php [L]
That way, our static files were handled properly, and all the rest was redirected to index.php which handled the parsing and went on to query the right results (eg : example.com/section1/category1, would redirect to the main page, and send a query through the socket for section1,category1 items.
I've tried modifying my main route in index.js to add a wildcard, but it fails to handle the static files (RewriteCond $1 !^(*static extensions*) )
router.get('/', function (req, res) {
...
}
This one works fine for the use case where the user starts at the frontpage, but (obviously) gives me non-existing routes if I want to access directly /sec1/cat1
router.get('*', function (req, res) {
...
}
This one redirects correctly, but cannot find the static files.
Any idea how to handle the static files in a similar fashion than the RewriteCond does?

Yii 404 page - override parent htaccess

I'm using the Yii framework at my company site.
I have a frontend at domain.com/... and a Yii based app at domain.com/app/.. .
We recently added a 404 page to the frontend site, with htaccess's ErrorDocument handler at the frontend. Problem is, the Yii app inherits from that 404, which gives a bad page. How can I force it to use Yii's embedded error handling page?
Thanks in advance.
There are 2 good article talking bout this:
How to use default layout for error pages instead of errorXXX views
Handling errors using an action
The idea is, you create a action in out main Controller that will handle all page errors, so, you can change your htaccess to redirect your application to the Controller:
domain.com/site/error
Ended up using a RewriteCond redirection instead of ErrorDocument, resulting in a "rule" for the file to be redirected. Basically something like this:
RewriteCond %{REQUEST_URI} !^/app
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* /404.php
Basically this means, "if file requested is not valid file, use this rewriterule". The first condition is to make sure it excludes the "app" folder, so it handles its own errors.

CakePHP: Can you globally modify all links to point to another directory?

My CakePHP app lives inside a subdirectory to keep it from crashing into a Wordpress installation that powers part of the website:
example.com/ <--root
/_wp <--Wordpress installed here
/page1
/page2
/_cake <--CakePHP installed here
/page3
/page4
To maintain consistency, I'm using mod_rewrite rules to rewrite URLs from example.com/_cake/pageX to example.com/pageX etc. This basically works, but CakePHP still creates links with /_cake/pageX. So if a user hovers over a link, the "_cake" will show up in the bottom of the browser and of course in the source code.
Is there a way to configure CakePHP to think it's actually in the site root so it creates the desired URLs for links etc?
I haven't found a way to configure CakePHP the way you want.
If you create your links with HtmlHelper::link or Router::url, you can add a member $url['base'] = false to the $url array argument. This prevents the _cake prefix being inserted in front of the URL.
As an alternative, you can create your own link() or url() function, which calls HtmlHelper::link and always adds base = false.
For this to work, you must also have a .htaccess in the document root, which rewrites the requests to their real destination
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /_cake/$0 [L]
You must also pay attention to requests destined for the _wp directory.

Resources