Welcome Guest, Not a member yet? Register   Sign In
CI routing issue with multiple htaccess files (BUG?)
#1

(This post was last modified: 11-11-2015, 12:57 AM by decay.)

Can someone please help me with this? Ok, let me try up explain this a bit. I will also include a full demo project with a freshly downloaded copy of CI that shows my issue. Look at the very bottom of the post and i will mention for those who wants to go straight there.

Im trying to make a site that is a seperate frontend html and seperate api backend with CI. one of the other rquirments is that, i need to make scheduled deployments, meaning that i want to schedule a new version to be servered to users at midnight of 2015-12-31 for example. Im using htaccess to server diffeernt folders. My folder structure is as follows

/.htacces : this file is responsible for serving different versions depending on timestamp
/current/ : this is the container folder for the current version. in production this folder might be called V1, V2, V3 etc.
/current/api/ci/ : this is where the CI code lives. For sake of demo, im putting a fresh version of CI downloaded from the website here
/current/api/ci/.htaccess : the typical CI htaccess that points requests to the index.php
/current/bin/ : this is where the frontend files lives (html/css/js/assets etc).
/current/.htaccessthis htaccess is responsible for saying if the request has /api in it, look in the api folder, but for all other requests, look in bin folder. 


Easy enough?

So at the end of the day:
example.com, example.com/blah etc should serve index.html (or php) from the /current/bin/ folder.
example.com/api/ci/ should display the welcome page for CI.


What is happening, the ISSUE/BUG:
When i goto example.com/api/ci/ (or anything more at the end of the url), the CI code actually gets picked up, if you vardump the $_REQUEST from the index.php you see that all the url variables are actually passed (ie: example.com/api/ci/admin passes "admin" correctly to CI), but always throws a 404. So, CI can see the $_REQUEST, but it doesnt render the controller/view. 

Why is this happening?

How to Trigger/Test/Demo:
attached is a demo project, host it at a root of any domain/subdomain. and navigate to example.com or example.com/blah and you see the /current/bin/index.php being served. But if you navigate to example.com/api/ci/, you can see a 404 from CI (it should be displaying the welcome page). Thoughts?

Demo Projecthttps://www.dropbox.com/s/pp1ht06590mstx...o.zip?dl=0
Reply
#2

ok, i debugged this further... maybe someone can help me with the last bit...

The problem comes from the system/core/URI.php. and look for the function definition: "_parse_request_uri". Near the top of this function, there is a nested if statement as follows:

PHP Code:
        if (isset($_SERVER['SCRIPT_NAME'][0]))
        {
            
// A
            
if (strpos($uri$_SERVER['SCRIPT_NAME']) === 0)
            {
                
// B
                
$uri = (string) substr($uristrlen($_SERVER['SCRIPT_NAME']));
            }
            elseif (
strpos($uridirname($_SERVER['SCRIPT_NAME'])) === 0)
            {
                
// C
                
$uri = (string) substr($uristrlen(dirname($_SERVER['SCRIPT_NAME'])));
            }
        } 

If you look at the above code, i put some A, B, and C comments in there to explain. So the 2 scenarios are:

example.com/api/ci/ : this causes a 404. on the above code, it hits A but nothing else. So after this code block, the $uri variable remains "api/ci" which is incorrect. To debug this further, the elseif statement that looks as the "dirname($_SERVER['SCRIPT_NAME'])" outputs "/current/api/ci" and it looks if that is a substring of the URL, which clearly isnt because the htaccess file rewrites the URL and removes current. Instead of looking at the url and script location, shouldnt this be looking at the $_REQUEST or $_GET variables passed in from the common htaccess file's url rewriting?

example.com/current/api/ci/ : this is incorrect url, but somehow actually displays the controller correctly. Lets use this as an example of a traditional setup of CI. In this instance, "dirname($_SERVER['SCRIPT_NAME'])" also outputs "/current/api/ci" and since this exists in the URL it triggers C. which correctly rewrites the URL and all is well.

So, clearly this is a BUG. Can we/I please have a fix? atleast a hack to get me going?

TY in advance Big Grin
Reply
#3

(This post was last modified: 11-11-2015, 11:07 PM by decay.)

Here is my TEMPORARY fix.

Change the CI htaccess at the root of the CI project to be this (mainly the last line):

Code:
DirectoryIndex index.php
RewriteEngine on

RewriteCond $1 !^(index\.php|(.*)\.swf|forums|images|css|downloads|jquery|js|robots\.txt|favicon\.ico)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ ./index.php?$1&ci_url=$1 [L,QSA]


Then modify the above mentioned if statement in the URI.php to the following (the else part of the 2nd if statement):

PHP Code:
if (isset($_SERVER['SCRIPT_NAME'][0]))
{
 
 // A
 
 if (strpos($uri$_SERVER['SCRIPT_NAME']) === 0)
 
 {
 
    // B
 
    $uri = (string) substr($uristrlen($_SERVER['SCRIPT_NAME']));
 
 }
 
 elseif (strpos($uridirname($_SERVER['SCRIPT_NAME'])) === 0)
 
 {
 
    // C
 
    $uri = (string) substr($uristrlen(dirname($_SERVER['SCRIPT_NAME'])));
 
 }else{
 
    if(isset($_GET['ci_url'])){
 
       $uri '/' $_GET['ci_url'];
 
    }else{
 
       $uri '/';
 
    }
 
 }



This fixes the issue for now, im not sure what other implications this may cause. 
Reply
#4

Have you included in the .htaccess file in the api/ci/ folder the correct rewrite base with the correct path?

Code:
RewriteBase /**additional_path_setting**/

I am only guessing here as I struggle with .htaccess at the best of times and have not downloaded your example, but if I have a sub CI installation somewhere I often forget this and get the behavior you have described.

Hope that helps in some way,

Paul.
Reply
#5

(This post was last modified: 11-12-2015, 05:59 AM by Martin7483.)

I think this should work.

Place this in your main .htaccess file
Code:
RewriteCond %{REQUEST_URI} ^/api/ci.*$ [NC]
RewriteRule ^(.*)$ /current/api/ci/index.php/$1 [QSA,L]

EDIT:
Is the a BUG? I don't think it is. If your wish is to have a different code base for each api version, why not use sub domains?
Have your htaccess on the main domain route the request to a sub domain containing the requested api version. No need for complex sub htaccess setups.
Reply
#6

(This post was last modified: 11-12-2015, 01:20 PM by decay.)

(11-12-2015, 05:39 AM)Martin7483 Wrote: Is the a BUG? I don't think it is. If your wish is to have a different code base for each api version, why not use sub domains?
Have your htaccess on the main domain route the request to a sub domain containing the requested api version. No need for complex sub htaccess setups.

i didnt reveals everything about the scenario, but please work within the parameters given. Anyway, the bug is within CI as mentioned on my earlier replies. I will have a look and give your htaccess suggestion a go, but my earlier reply essentially fixes the problem.

Just to elaborate my claim that CI has the bug, why on earth are we passing in the "controller/action" to the index.php of CI (using the CI's reccomended htaccess) while CI ignores it and uses the script location to find the controller/action? That is pretty silly, and if anyone is claiming that this is not a bug, i will likely stop using CI.
Reply
#7

example.com/api/ci should load your default CI controller?
Reply
#8

(11-12-2015, 04:32 PM)Martin7483 Wrote: example.com/api/ci should load your default CI controller?

Yes, you would think so right? But it doesnt. Guessing you didnt read my original post entirely. Incase you missed the part where i talked about it, this displays the default CI's 404 page instead of showing the default controller/action. Again, the error lies in CI core code, which is also pointed out on one of the replies.
Reply
#9

(This post was last modified: 11-13-2015, 04:58 AM by Martin7483.)

I have an answer you might like

I downloaded your demo and did the following changes:

./current/.htaccess:
Code:
# If no api present, Go to bin
RewriteCond $1 !^(api|robots\.txt)
RewriteRule ^(.*)$ /current/bin/$1 [L]
#If api present, Go to API
RewriteRule ^(.*)$ /current/api/ci/index.php/$1 [L]

./current/api/ci/.htaccess:
Disabled all rules and conditions

Added this to the beginning of ./current/api/ci/index.php:
PHP Code:
//You will need to reset the $_SERVER['REQUEST_URI'] for CI to work as normal
// If you plan on using an URL_SUFFIX define it here and use the define in your config
define('URL_SUFFIX'".html");
// Get the current request URI
$request explode('/',$_SERVER['REQUEST_URI']);
// Remove the unwanted segments
$remove = array('','api');
foreach(
$request as $key => $segment) {
 
   $segment str_replace(URL_SUFFIX""$segment);
 
   ifin_array($segment$remove) ) {
 
       unset($request[$key]);
 
   }
}
// Create the new request uri
$request_uri implode('/'$request);
// Rewrite the $_SERVER['REQUEST_URI'] to include the needed segments
$_SERVER['REQUEST_URI'] = str_replace(pathinfo(__FILE__PATHINFO_BASENAME), ""$_SERVER['SCRIPT_NAME']).$request_uri

Now when I called http://decay.mkb the request ended up in bin
And when I called http://decay.mkb/api the request ended up displaying the default CI welcome controller

Hope this is what you are looking for
Reply




Theme © iAndrew 2016 - Forum software by © MyBB