<p>I would like to share with you my <strong>new and improved index.php</strong>.</p>

<p>With the old version the control panel login didn't work all the time.</p>

<p>I've rearranged the code and replaced</p>

<pre><code>if (!isset($_GET['p']) || strncmp($_GET['p'], 'admin', 5) !== 0)
</code></pre>

<p>with</p>

<pre><code>if (strncmp($_SERVER['PATH_INFO'], '/admin', 6) === 0 || strncmp($_GET['p'], 'admin', 5) === 0)
</code></pre>

<p>This is the complete code example:</p>

<p>

<pre><code>// Make sure this is a Control Panel request
if (strncmp($_SERVER['PATH_INFO'], '/admin', 6) === 0 || strncmp($_GET['p'], 'admin', 5) === 0)
{

    // Path to your craft/ folder
    $craftPath = '../craft';

    // Do not edit below this line
    $path = rtrim($craftPath, '/').'/app/index.php';

    if (!is_file($path))
    {
        if (function_exists('http_response_code'))
        {
            http_response_code(503);
        }
        exit('Temporary error. Could not find the CMS folder.');
    }
    require_once $path;

}
else
{

    // Set language paths
    $paths = array(
        'de' =&gt; '/de/',
        'it' =&gt; '/it/',
        'en' =&gt; '/en/'
    );

    // Get browser's preferred languages
    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) &amp;&amp; preg_match_all('/([\w\-_]+)\s*(?:;\s*q\s*=\s*(\d*\.\d*))?/', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches, PREG_SET_ORDER))
    {
        $languages = array();
        $weights   = array();

        // Fill arrays with all matches
        foreach ($matches as $match)
        {
            $languages[] = strtolower(substr($match[1], 0, 2));
            $weights[]   = !empty($match[2]) ? floatval($match[2]) : 1;
        }

        // Sort languages by their weight
        array_multisort($weights, SORT_NUMERIC, SORT_DESC, $languages);

        // Find first match
        foreach ($languages as $language)
        {
            if (isset($paths[$language]))
            {
                $matchingLanguage = $language;
                break;
            }
        }
    }

    // Set default language
    if (!isset($matchingLanguage))
    {
        $matchingLanguage = 'de';
    }

    // Redirect
    $url = $paths[$matchingLanguage].(isset($_GET['p']) ? $_GET['p'] : '');
    header('Location: '.$url, true, 302);

}
</code></pre>

CC BY-SA 3.0
2015-02-25T09:19:39.817Z
If you use the **Sitemap plugin** from PutYourLightsOn use this: `if (strncmp($_SERVER['PATH_INFO'], '/admin', 6) === 0 || strncmp($_GET['p'], 'admin', 5) === 0 || strncmp($_GET['p'], 'sitemap.xml', 11) === 0)`
Christian Steger
CC BY-SA 3.0
2016-01-29T15:49:33.103Z
Hi, I used this code but an update to craft 2.5 and php7 somehow broke it. This is the error message I get: Notice: Undefined index: PATH_INFO in /home/...etc.../index.php on line 3. Any hint to why this happened?
outline4
CC BY-SA 3.0
2016-02-04T12:39:47.817Z
Sorry, no idea. I use this code actually with PHP 7.0.2 without errors.
Christian Steger
CC BY-SA 3.0
2016-02-04T17:02:25.127Z
Hi, it was a server problem. They forgot to set the path_info value, and they've tuned some error settings. It's all good, and blazingly fast :)
outline4
CC BY-SA 3.0
2018-04-18T10:27:02.673Z
Is this still a viable solution in 2018? Looking for exactly the same functionality …
Tobias S.
CC BY-SA 4.0
2019-10-04T19:16:58.633Z
has anybody adapted this for craft 3?
outline4
CC BY-SA 3.0
2015-02-24T23:22:12.447Z
2015-02-24T23:22:12.447Z
Christian Steger
<p>I would suggest making the “admin” check a little more strict:</p>



<pre class="lang-php prettyprint-override"><code>// Make sure this isn't a CP request
if (!isset($_GET['p']) || strncmp($_GET['p'], 'admin', 5) !== 0)
{
    // ...
</code></pre>

<p>(Assuming you’re using the <a href="http://buildwithcraft.com/help/remove-index.php" rel="nofollow">recommended .htaccess redirect rule</a>, by the time the request hits index.php, the original request URI will be available as <code>$_GET['p']</code>.)</p>

<p>The Accept-Language header can actually include multiple languages, so you might want to consider looking at all of them, sorted by weight. <a href="http://buildwithcraft.com/classreference/services/HttpRequestService#getBrowserLanguages-detail" rel="nofollow">HttpRequestService::getBrowserLanguages()</a> has some example code on how to do that.</p>

<p>A 302 redirect would probably be more appropriate than 301. You wouldn’t want Google to think that <a href="http://example.com/" rel="nofollow">http://example.com/</a> should always really be <a href="http://example.com/en/" rel="nofollow">http://example.com/en/</a> or whatever this script might end up sending it to, and people could theoretically change their browser’s language preferences.</p>

<p>You also might want to include <code>$_GET['p']</code> in your redirect location. Right now you’re just sending all traffic off to the locale-specific homepage, which is why 404s aren’t working as expected.</p>

<p>To put it all together, here’s what you might want to do:</p>

<pre class="lang-php prettyprint-override"><code>&lt;?php

// Make sure this isn't a CP request
if (!isset($_GET['p']) || strncmp($_GET['p'], 'admin', 5) !== 0)
{
    // Language paths
    $paths = array(
        'de' =&gt; '/de/',
        'it' =&gt; '/it/',
        'en' =&gt; '/en/'
    );

    // Get the browser's preferred languages
    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) &amp;&amp; preg_match_all('/([\w\-_]+)\s*(?:;\s*q\s*=\s*(\d*\.\d*))?/', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches, PREG_SET_ORDER))
    {
        $languages = array();
        $weights = array();

        foreach ($matches as $match)
        {
            $languages[] = strtolower(substr($match[1], 0, 2));
            $weights[] = !empty($match[2]) ? floatval($match[2]) : 1;
        }

        // Sort the languages by their weight
        array_multisort($weights, SORT_NUMERIC, SORT_DESC, $languages);

        // Find the first match
        foreach ($languages as $language)
        {
            if (isset($paths[$language]))
            {
                $matchingLanguage = $language;
                break;
            }
        }
    }

    // Default to German
    if (!isset($matchingLanguage))
    {
        $matchingLanguage = 'de';
    }

    // Redirect
    $url = $paths[$matchingLanguage].(isset($_GET['p']) ? $_GET['p'] : '');
    header('Location: '.$url, true, 301);
}
else
{
    // Path to your craft/ folder
    $craftPath = '../craft';

    // Do not edit below this line
    $path = rtrim($craftPath, '/').'/app/index.php';

    if (!is_file($path))
    {
        exit('Temporary error. Could not find the CMS folder.');
    }

    require_once $path;
}
</code></pre>

CC BY-SA 3.0
2014-08-24T20:08:00.893Z
Please replace && with || in the complete code example. Works great. Thanks
Christian Steger
CC BY-SA 3.0
2015-01-19T21:15:09.180Z
If I use this code on my site, it works great, but I'm unable to login to the admin panel anymore. It keeps giving me an "unknown error". Any ideas how to solve this?
Tom De Smet
CC BY-SA 3.0
2015-02-24T23:27:00.880Z
@TomDeSmet Please have a look at my new answer. It solves your problem.
Christian Steger
CC BY-SA 3.0
2014-08-23T16:14:12.597Z
2014-08-25T16:12:58.090Z
2014-08-25T16:12:58.090Z
Brandon Kelly
<p>I have written this simple redirect code in the main index.php file. 
Now I need to know if this code can somehow cause problems with Craft:</p>

<pre>
    // Check if URI contains cpTrigger
    $pos = strpos($_SERVER['REQUEST_URI'], 'admin');

    if ($pos === false) {

        // Language paths
        $paths = array(
            'de'=>'/de/',
            'it'=>'/it/',
            'en'=>'/en/'
        );

        // Browser language
        $language = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);

        // Default language
        if (!isset($paths[$language])) {
            $language = 'de';
        }

        // Redirect
        header('HTTP/1.1 301 Moved Permanently'); 
        header('Location:' . $paths[$language]);

    } else {

        // Path to your craft/ folder
        $craftPath = '../craft';

        // Do not edit below this line
        $path = rtrim($craftPath, '/').'/app/index.php';

        if (!is_file($path)) {
            exit('<strong>Temporary error.</strong> Could not find the CMS folder.');
        }

        require_once $path;

    }
</pre>

<p>Only the 404 page doesn't load with www.example.com/idontexist but loads instead the homepage.
(www.example.com/<strong>en</strong>/idontexist loads as expected the 404 page)</p>

<p>Perhaps somebody knows a better solution?</p>

CC BY-SA 3.0
2018-04-18T10:31:05.417Z
what exactly do you mean by main index.php? just the one in the public folder or also the ones in the sub-directories for the locales, e.g. public/de or public/es?
Tobias S.
<redirect>
302 redirects to locales in main index.php
# 302 redirects to locales in main index.php

(Asked by: username_0 on 2014-08-22)

I have written this simple redirect code in the main index.php file. 
Now I need to know if this code can somehow cause problems with Craft:

    // Check if URI contains cpTrigger
    $pos = strpos($_SERVER['REQUEST_URI'], 'admin');

    if ($pos === false) {

        // Language paths
        $paths = array(
            'de'=>'/de/',
            'it'=>'/it/',
            'en'=>'/en/'
        );

        // Browser language
        $language = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);

        // Default language
        if (!isset($paths[$language])) {
            $language = 'de';
        }

        // Redirect
        header('HTTP/1.1 301 Moved Permanently'); 
        header('Location:' . $paths[$language]);

    } else {

        // Path to your craft/ folder
        $craftPath = '../craft';

        // Do not edit below this line
        $path = rtrim($craftPath, '/').'/app/index.php';

        if (!is_file($path)) {
            exit('Temporary error. Could not find the CMS folder.');
        }

        require_once $path;

    }

Only the 404 page doesn't load with www.example.com/idontexist but loads instead the homepage.
(www.example.com/en/idontexist loads as expected the 404 page)
Perhaps somebody knows a better solution?

**Tags:** redirect
> **Comments:**
> **username_1**: what exactly do you mean by main index.php? just the one in the public folder or also the ones in the sub-directories for the locales, e.g. public/de or public/es?  

---

## 2 answers

### Answer by username_0 on 2015-02-24. Score: 2 | Accepted answer

I would like to share with you my new and improved index.php.
With the old version the control panel login didn't work all the time.
I've rearranged the code and replaced
if (!isset($_GET['p']) || strncmp($_GET['p'], 'admin', 5) !== 0)

with
if (strncmp($_SERVER['PATH_INFO'], '/admin', 6) === 0 || strncmp($_GET['p'], 'admin', 5) === 0)

This is the complete code example:

// Make sure this is a Control Panel request
if (strncmp($_SERVER['PATH_INFO'], '/admin', 6) === 0 || strncmp($_GET['p'], 'admin', 5) === 0)
{

    // Path to your craft/ folder
    $craftPath = '../craft';

    // Do not edit below this line
    $path = rtrim($craftPath, '/').'/app/index.php';

    if (!is_file($path))
    {
        if (function_exists('http_response_code'))
        {
            http_response_code(503);
        }
        exit('Temporary error. Could not find the CMS folder.');
    }
    require_once $path;

}
else
{

    // Set language paths
    $paths = array(
        'de' => '/de/',
        'it' => '/it/',
        'en' => '/en/'
    );

    // Get browser's preferred languages
    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && preg_match_all('/([\w\-_]+)\s*(?:;\s*q\s*=\s*(\d*\.\d*))?/', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches, PREG_SET_ORDER))
    {
        $languages = array();
        $weights   = array();

        // Fill arrays with all matches
        foreach ($matches as $match)
        {
            $languages[] = strtolower(substr($match[1], 0, 2));
            $weights[]   = !empty($match[2]) ? floatval($match[2]) : 1;
        }

        // Sort languages by their weight
        array_multisort($weights, SORT_NUMERIC, SORT_DESC, $languages);

        // Find first match
        foreach ($languages as $language)
        {
            if (isset($paths[$language]))
            {
                $matchingLanguage = $language;
                break;
            }
        }
    }

    // Set default language
    if (!isset($matchingLanguage))
    {
        $matchingLanguage = 'de';
    }

    // Redirect
    $url = $paths[$matchingLanguage].(isset($_GET['p']) ? $_GET['p'] : '');
    header('Location: '.$url, true, 302);

}

> **Comments:**
> **username_0**: If you use the **Sitemap plugin** from PutYourLightsOn use this: `if (strncmp($_SERVER['PATH_INFO'], '/admin', 6) === 0 || strncmp($_GET['p'], 'admin', 5) === 0 || strncmp($_GET['p'], 'sitemap.xml', 11) === 0)`  
> **username_2**: Hi, I used this code but an update to craft 2.5 and php7 somehow broke it. This is the error message I get: Notice: Undefined index: PATH_INFO in /home/...etc.../index.php on line 3. Any hint to why this happened?  
> **username_0**: Sorry, no idea. I use this code actually with PHP 7.0.2 without errors.  
> **username_2**: Hi, it was a server problem. They forgot to set the path_info value, and they've tuned some error settings. It's all good, and blazingly fast :)  
> **username_1**: Is this still a viable solution in 2018? Looking for exactly the same functionality …  
> **username_2**: has anybody adapted this for craft 3?  

---

### Answer by username_3 on 2014-08-23. Score: 4

I would suggest making the “admin” check a little more strict:
// Make sure this isn't a CP request
if (!isset($_GET['p']) || strncmp($_GET['p'], 'admin', 5) !== 0)
{
    // ...

(Assuming you’re using the recommended .htaccess redirect rule, by the time the request hits index.php, the original request URI will be available as $_GET['p'].)
The Accept-Language header can actually include multiple languages, so you might want to consider looking at all of them, sorted by weight. HttpRequestService::getBrowserLanguages() has some example code on how to do that.
A 302 redirect would probably be more appropriate than 301. You wouldn’t want Google to think that http://example.com/ should always really be http://example.com/en/ or whatever this script might end up sending it to, and people could theoretically change their browser’s language preferences.
You also might want to include $_GET['p'] in your redirect location. Right now you’re just sending all traffic off to the locale-specific homepage, which is why 404s aren’t working as expected.
To put it all together, here’s what you might want to do:
 '/de/',
        'it' => '/it/',
        'en' => '/en/'
    );

    // Get the browser's preferred languages
    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && preg_match_all('/([\w\-_]+)\s*(?:;\s*q\s*=\s*(\d*\.\d*))?/', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches, PREG_SET_ORDER))
    {
        $languages = array();
        $weights = array();

        foreach ($matches as $match)
        {
            $languages[] = strtolower(substr($match[1], 0, 2));
            $weights[] = !empty($match[2]) ? floatval($match[2]) : 1;
        }

        // Sort the languages by their weight
        array_multisort($weights, SORT_NUMERIC, SORT_DESC, $languages);

        // Find the first match
        foreach ($languages as $language)
        {
            if (isset($paths[$language]))
            {
                $matchingLanguage = $language;
                break;
            }
        }
    }

    // Default to German
    if (!isset($matchingLanguage))
    {
        $matchingLanguage = 'de';
    }

    // Redirect
    $url = $paths[$matchingLanguage].(isset($_GET['p']) ? $_GET['p'] : '');
    header('Location: '.$url, true, 301);
}
else
{
    // Path to your craft/ folder
    $craftPath = '../craft';

    // Do not edit below this line
    $path = rtrim($craftPath, '/').'/app/index.php';

    if (!is_file($path))
    {
        exit('Temporary error. Could not find the CMS folder.');
    }

    require_once $path;
}

> **Comments:**
> **username_0**: Please replace && with || in the complete code example. Works great. Thanks  
> **username_4**: If I use this code on my site, it works great, but I'm unable to login to the admin panel anymore. It keeps giving me an "unknown error". Any ideas how to solve this?  
> **username_0**: @TomDeSmet Please have a look at my new answer. It solves your problem.  

---

