FOSRestBundle double leading slash in route - symfony

I'm trying to handle a wrongly coded leading slash route in an Android application. It is trying to reach our system using:
//api/1.0/store/products/video/USD.json
but should normaly be
/api/1.0/store/products/video/USD.json
so this is causing a route not found exception in our app.
I cannot change the android application! I must find a way to make the wrong route work!
What i've tried:
Splitting the controller in two, one with the standard "/api" prefix and one with a prefix of "//api", didn't work, i think FOSRestBundle is fixing that for me live, so all my routes are still only 1 leading slash
Using a rewrite rule in .htaccess (See below) to rewrite the rule before i get problems, this would be the best strategy as it would keep my app and integration tests clean
Attempt using HTACCESS
RewriteRule /api/(.*) api/$1 [L]
This rule is supposed to work if i test it on "http://martinmelin.se/rewrite-rule-tester/" but in my htaccess it doesn't. Here's the content of my .htaccess.
Can anyone help me figure out a solution?
# Use the front controller as index file. It serves as a fallback solution when
# every other rewrite/redirect fails (e.g. in an aliased environment without
# mod_rewrite). Additionally, this reduces the matching process for the
# start page (path "/") because otherwise Apache will apply the rewriting rules
# to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl).
DirectoryIndex index.php
<IfModule mod_rewrite.c>
RewriteEngine On
# Rewrite double leading slash routes to single leading slash routes
RewriteRule /api/(.*) api/$1 [L]
# Determine the RewriteBase automatically and set it as environment variable.
# If you are using Apache aliases to do mass virtual hosting or installed the
# project in a subdirectory, the base path will be prepended to allow proper
# resolution of the app.php file and to redirect to the correct URI. It will
# work in environments without path prefix as well, providing a safe, one-size
# fits all solution. But as you do not need it in this case, you can comment
# the following 2 lines to eliminate the overhead.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
# Sets the HTTP_AUTHORIZATION header removed by apache
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect to URI without front controller to prevent duplicate content
# (with and without `/app.php`). Only do this redirect on the initial
# rewrite by Apache and not on subsequent cycles. Otherwise we would get an
# endless redirect loop (request -> rewrite to front controller ->
# redirect -> request -> ...).
# So in case you get a "too many redirects" error or you always get redirected
# to the start page because your Apache does not expose the REDIRECT_STATUS
# environment variable, you have 2 choices:
# - disable this feature by commenting the following 2 lines or
# - use Apache >= 2.3.9 and replace all L flags by END flags and remove the
# following RewriteCond (best solution)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^index\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L]
# If the requested filename exists, simply serve it.
# We only want to let Apache serve files and not directories.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .? - [L]
# Rewrite all other queries to the front controller.
RewriteRule .? %{ENV:BASE}/index.php [L]
</IfModule>
<IfModule !mod_rewrite.c>
<IfModule mod_alias.c>
# When mod_rewrite is not available, we instruct a temporary redirect of
# the start page to the front controller explicitly so that the website
# and the generated links can still be used.
RedirectMatch 302 ^/$ /index.php/
# RedirectTemp cannot be used instead
</IfModule>
</IfModule>

Okay, I tried, and failed to match the requested uri, so I will suggest you different approach, if you find it suitable. How about if we just replace all double leading slashes with single ones?
What I mean is something like that:
RewriteCond %{REQUEST_URI} ^(.*)//(.*)$
RewriteRule . %1/%2 [R=301,L]
The following tests on my project were successful:
/admin//orders => /admin/orders
//admin//orders//5 => /admin/orders/5
And lastly, I pasted yours as well:
//api/1.0/store/products/video/USD.json
gave this:
No route found for "GET /api/1.0/store/products/video/USD.json"
which is I believe what we are looking for. Hope you can use this solution as a temporary one until someone else provides a better one.

Related

Wordpress/Apache rewrite/redirect rule and regex

I need to do some apache rewrite/redirect rules to external webservice in case of 404 error for specific file extensions: .jpg, .png, etc. Wordpress is used here.
So, if 404 occurs at:
https://test.com/folder/subfolder/year/month/filename.jpg
I want to redirect it to:
https://test1.com/folder/subfolder/year/month/filename.jpg (external webservice, not the same phisical server)
I've tried such a configuration in htaccess, didn't work as expected:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*) test1.com/folder/subfolder//$year$\/$month$\/([^\s]+(\.(?i)(png | jpg | gif | svg))$)/
Do you have any ideas how to do it right way?
Any suggestions appreciated.
With your shown samples, attempts; please try following htaccess rules file. These rules are written as per shown domain names which are samples/tests, so you need to change values as per your actual values when you use them in your system. We also need to make sure that both (test.com and test1.com) are sharing same directory structure in your actual apache server.
Also make sure to clear your browser cache before testing your URLs.
RewriteEngine ON
RewriteCond %{HTTP_HOST} ^(?:www\.)?test\.com$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/?$ https://test1.com/$1 [R=301,L]
To "redirect" URLs of the form /folder/subfolder/<year>/<month>/<file>.<png|jpg|gif|svg> where /folder/subfolder/ is static and the other elements are variable and which do not exist on the filesystem you would need to do something like the following before the WordPress code block. ie. before the # BEGIN WordPress section.
# Redirect certain non-existent image files to another server
RewriteRule ^folder/subfolder/\d{4}/\d\d/[\w-]\.(png|jpg|gif|svg)$ https://test1.com/$0 [R=302,L]
# BEGIN WordPress
:
The <year> is a 4-digit number and <month> is a 2-digit number. The filename can consist of the characters 0-9, a-z, A-Z, _ (underscore) and - (hyphen).
This should presumably be a 302 (temporary) redirect, not a 301 (permanent), otherwise if the resource should become available at the source domain then it won't be accessible to those users who have visited the URL before (they will be redirected from cache).
To avoid the external redirect it may be preferable to "proxy" the request to the other domain. (This is invisible to the end user.) Although this potentially involves additional configuration server-side, as you would need to configure the source server as a "reverse proxy". You can then replace the R=302 flag in the above rule with P (proxy).

htaccess restrict access to ALL pages but referrer

I managed to restrict access to my site using the .htaccess directives below. It works pretty well BUT I found that people other than referrer success to access direct page like https://example.com/**pages**/ and from there can go back to home. How can I restrict to all site but the referrer (so all tree from my root URL).
# Serve everyone from specific-domain (and internal requests)
RewriteCond %{HTTP_REFERER} ^https?://www\.your-domain\.com/ [OR]
RewriteCond %{HTTP_REFERER} ^https?://www\.specific-domain\.com/
RewriteRule ^ - [L]
# everybody else receives a forbidden
RewriteRule ^ - [F]
From discussion on your other question, it seems you have been putting these directives in the wrong place. It is a WordPress site and the directives have been placed after the WordPress front-controller, ie. after the # BEGIN WordPress ... # END WordPress code block.
This is actually a very common mistake. But order matters.
By placing them at the end of the file they are simply never going to be processed for requests to example.com/<wordpress-url>, because the request has already been routed to the WordPress front-controller (index.php).
These blocking directives need to go at the very top of the .htaccess file. Importantly they must go before the # BEGIN WordPress section.
You should NOT place these directives inside the WordPress code block since WordPress maintains this section and will likely overwrite any custom directives you place here.
You do not need to repeat the RewriteEngine On directive (which appears later in the file - the order of this directive does not matter). In fact, if there are multiple RewriteEngine directives then the last directive wins and controls the entire file/context.
UPDATE#1:
is there a way to exclude a single page from the directives so that this page can still be available even from non referrer - it would be a login page
Yes, you can add an additional condition to the first block that checks for this URL. For example:
# Serve everyone from specific-domain (and internal requests)
RewriteCond %{REQUEST_URI] ^/login$ [OR]
RewriteCond %{HTTP_REFERER} ^https?://www\.your-domain\.com/ [OR]
RewriteCond %{HTTP_REFERER} ^https?://www\.specific-domain\.com/
RewriteRule ^ - [L]
# Everybody else receives a forbidden
RewriteRule ^ - [F]
UPDATE#2:
However, since this is a WordPress site, you still need processing to continue to the front-controller (the # BEGIN WordPress section later in the file) in order to route the URLs. This would explain why you are seeing 404s for /<page> and other WordPress URLs despite the Referer presumably being set correctly.
To resolve this, change the [L] flag in the first RewriteRule to [S=1] (skip 1 rule), so instead of stopping further processing (the effect of the L / last flag), it simply skips the following rule that blocks access for everyone else. And continues on to the WordPress front-controller.
For example:
:
RewriteRule ^ - [S=1]
# Everybody else receives a forbidden
RewriteRule ^ - [F]
Alternatively, you could reverse the logic...
# Block everyone from "other" domains except for specific URLs
RewriteCond %{REQUEST_URI] !^/login$
RewriteCond %{HTTP_REFERER} !^https?://www\.your-domain\.com/
RewriteCond %{HTTP_REFERER} !^https?://www\.specific-domain\.com/
RewriteRule ^ - [F]
# BEGIN WordPress
:

Symfony 4, access to public/index.php OK in dev mode, access KO (404) in prod mode

In development mode, I use an apache server, I go to my App via localhost/myApp/public/index.php . I want test prod mod with my symfony 4 application.
I changed the APP_ENV variable to "prod" (in the .env file)
I installed composer packages via the command composer install --no-dev
But now, when I open my browser and go to localhost/myApp/public/index.php, I get a symfony 404 error page :
The apache configuratin seems good (I can access to the website without any problems in dev mode and I get a 404 not found built by symfony, the index.php is found by apache). I don't understand where may be the problem :/
EDIT : below, the content of the .htaccess file (in the public directory). I don't modify it, this is the symfony default htaccess file :
# Use the front controller as index file. It serves as a fallback solution when
# every other rewrite/redirect fails (e.g. in an aliased environment without
# mod_rewrite). Additionally, this reduces the matching process for the
# start page (path "/") because otherwise Apache will apply the rewriting rules
# to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl).
DirectoryIndex index.php
# By default, Apache does not evaluate symbolic links if you did not enable this
# feature in your server configuration. Uncomment the following line if you
# install assets as symlinks or if you experience problems related to symlinks
# when compiling LESS/Sass/CoffeScript assets.
# Options FollowSymlinks
# Disabling MultiViews prevents unwanted negotiation, e.g. "/index" should not resolve
# to the front controller "/index.php" but be rewritten to "/index.php/index".
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
# Determine the RewriteBase automatically and set it as environment variable.
# If you are using Apache aliases to do mass virtual hosting or installed the
# project in a subdirectory, the base path will be prepended to allow proper
# resolution of the index.php file and to redirect to the correct URI. It will
# work in environments without path prefix as well, providing a safe, one-size
# fits all solution. But as you do not need it in this case, you can comment
# the following 2 lines to eliminate the overhead.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
# Sets the HTTP_AUTHORIZATION header removed by Apache
RewriteCond %{HTTP:Authorization} .
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect to URI without front controller to prevent duplicate content
# (with and without `/index.php`). Only do this redirect on the initial
# rewrite by Apache and not on subsequent cycles. Otherwise we would get an
# endless redirect loop (request -> rewrite to front controller ->
# redirect -> request -> ...).
# So in case you get a "too many redirects" error or you always get redirected
# to the start page because your Apache does not expose the REDIRECT_STATUS
# environment variable, you have 2 choices:
# - disable this feature by commenting the following 2 lines or
# - use Apache >= 2.3.9 and replace all L flags by END flags and remove the
# following RewriteCond (best solution)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]
# If the requested filename exists, simply serve it.
# We only want to let Apache serve files and not directories.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
# Rewrite all other queries to the front controller.
RewriteRule ^ %{ENV:BASE}/index.php [L]
</IfModule>
<IfModule !mod_rewrite.c>
<IfModule mod_alias.c>
# When mod_rewrite is not available, we instruct a temporary redirect of
# the start page to the front controller explicitly so that the website
# and the generated links can still be used.
RedirectMatch 307 ^/$ /index.php/
# RedirectTemp cannot be used instead
</IfModule>
</IfModule>
Edit 3 : I created the php file foo.php in the dir public with <?php echo 'foo';?> and I can access to this file through my browser without any problem. Something is wrong with symfony but impossible to find where is my error...
Thank you for any help !
I am so stupid. In dev mode, the home page ('/') doesn't show a 404 but a page generated automatically by symfony.
The reason of why I have a 404 in prod mode is I don't create a controller with a route for the path '/'.
So, this 404 in home page in prod env is just logical

How can I change www.mysymfonypage.com/public to www.mysymfonypage.com?

When I locally open the url localhost:8000 then I see my main homepage.
I installed the apache pack (composer require symfony/apache-pack) and uploaded everything via ftp on my server.
This is the .htaccess file in my public folder:
# Use the front controller as index file. It serves as a fallback solution when
# every other rewrite/redirect fails (e.g. in an aliased environment without
# mod_rewrite). Additionally, this reduces the matching process for the
# start page (path "/") because otherwise Apache will apply the rewriting rules
# to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl).
DirectoryIndex index.php
# By default, Apache does not evaluate symbolic links if you did not enable this
# feature in your server configuration. Uncomment the following line if you
# install assets as symlinks or if you experience problems related to symlinks
# when compiling LESS/Sass/CoffeScript assets.
# Options FollowSymlinks
# Disabling MultiViews prevents unwanted negotiation, e.g. "/index" should not resolve
# to the front controller "/index.php" but be rewritten to "/index.php/index".
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
# Determine the RewriteBase automatically and set it as environment variable.
# If you are using Apache aliases to do mass virtual hosting or installed the
# project in a subdirectory, the base path will be prepended to allow proper
# resolution of the index.php file and to redirect to the correct URI. It will
# work in environments without path prefix as well, providing a safe, one-size
# fits all solution. But as you do not need it in this case, you can comment
# the following 2 lines to eliminate the overhead.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
# Sets the HTTP_AUTHORIZATION header removed by Apache
RewriteCond %{HTTP:Authorization} .
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect to URI without front controller to prevent duplicate content
# (with and without `/index.php`). Only do this redirect on the initial
# rewrite by Apache and not on subsequent cycles. Otherwise we would get an
# endless redirect loop (request -> rewrite to front controller ->
# redirect -> request -> ...).
# So in case you get a "too many redirects" error or you always get redirected
# to the start page because your Apache does not expose the REDIRECT_STATUS
# environment variable, you have 2 choices:
# - disable this feature by commenting the following 2 lines or
# - use Apache >= 2.3.9 and replace all L flags by END flags and remove the
# following RewriteCond (best solution)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]
# If the requested filename exists, simply serve it.
# We only want to let Apache serve files and not directories.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
# Rewrite all other queries to the front controller.
RewriteRule ^ %{ENV:BASE}/index.php [L]
</IfModule>
<IfModule !mod_rewrite.c>
<IfModule mod_alias.c>
# When mod_rewrite is not available, we instruct a temporary redirect of
# the start page to the front controller explicitly so that the website
# and the generated links can still be used.
RedirectMatch 307 ^/$ /index.php/
# RedirectTemp cannot be used instead
</IfModule>
</IfModule>
I open www.mysymfonypage.com and it redirects to the public folder, which is fine. But my URL is now www.mysymfonypage.com/public
How can I change this?
Really you should reconfigure your webserver to use /public as webroot - How do I change the root directory of an apache server?
Alternatively you could add
RewriteCond %{REQUEST_URI} !^/public/
RewriteRule ^(.*)$ /public/$1 [L,R=301]
after RewriteEngine On - BUT this will 301 redirect all your requests so that would likely cause issues / undesired behaviour somewhere along the line.

301 redirect loop in WordPress

Initially used a 301 to redirect www.example.com/ → www.example.com/wp
Unfortunately, I didn't read all the 'don't use 301 unless your 100% sure it's permanent' and now I need to revert back to the original domain.
At first, I tried to do a regular site url/wordpress url change in Setting/General in the admin dash. Saved over the old .htaccess on the root that had the original 301 redirect. Didn't work.
I moved everything to the root directory because I was getting a 'This webpage is a redirect loop' error page. Cleared cache on all browsers. Still getting the redirect loop error page.
Checked my url redirection here: http://www.digitalcoding.com/tools/url-redirect-check.html
I have two prompts, the first is going through fine, the second is a big fat X in red:
301 Moved Permanently: www.example.com/ → www.example.com301 Another Redirect Detected: www.example.com
.htaccess looks like this:
#Use PHP 5.4
AddType application/x-httpd-php54 .php
<IfModule mod_suphp.c>
suPHP_ConfigPath /opt/php54/lib/php.ini
</IfModule>
ErrorDocument 401 default
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Any insight?
Redirect 301 / http://www.example.com/
You get an endless loop because there is nothing in that code to tell it not to redirect www.example.com to itself.
You are correct that you cannot use the Redirect directive, and this is the reason; It is unconditional, and will cause a loop in the scenario you describe.
In order to prevent the loop, you must find a way to tell the code not to redirect www.example.com to itself. This can be done by using mod_rewrite, and specifically, the RewriteCond directive in mod_rewrite, to test the requested hostname and act accordingly:
Options +FollowSymLinks -MultiViews
RewriteEngine on
#
# if requested hostname is non-blank
RewriteCond %{HTTP_HOST} .
# and if requested hostname is NOT "www.example.com"
RewriteCond %{HTTP_HOST} !^www\.example\.com
# redirect to same object in correct domain
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
The first directive, Options, may or may not be required on your server. If it is not required, it may in fact not be allowed. Comment it out of you have trouble.
The second directive, RewriteEngine, is required once (and only once) at the top of your mod_rewrite code.
The third directive, the first RewriteCond, is only required if you do not use a name-based virtual (shared) server. It prevents an infinite loop if the client does not send a "Host" header with its request. Since it is impossible to access a name-based virtual server without a "Host" header, this line is not required on a name-based virtual server. No harm will come from leaving it in, except that it takes a little time to process it.
Note that this code will also redirect "example.com" to "www.example.com", and so serves to canonicalize your main domain name as well, preventing ranking dilution from having duplicate content on two variations of the domain.

Resources