Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-02-25T09:19:39.817Z
Answers.Text: 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)`
Answers.UserDisplayName: Christian Steger
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-01-29T15:49:33.103Z
Answers.Text: 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?
Answers.UserDisplayName: outline4
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-02-04T12:39:47.817Z
Answers.Text: Sorry, no idea. I use this code actually with PHP 7.0.2 without errors.
Answers.UserDisplayName: Christian Steger
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-02-04T17:02:25.127Z
Answers.Text: 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 :)
Answers.UserDisplayName: outline4
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-04-18T10:27:02.673Z
Answers.Text: Is this still a viable solution in 2018? Looking for exactly the same functionality …
Answers.UserDisplayName: Tobias S.
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-10-04T19:16:58.633Z
Answers.Text: has anybody adapted this for craft 3?
Answers.UserDisplayName: outline4
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-02-24T23:22:12.447Z
Answers.LastActivityDate: 2015-02-24T23:22:12.447Z
Answers.UserDisplayName: Christian Steger
Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-08-24T20:08:00.893Z
Answers.Text: Please replace && with || in the complete code example. Works great. Thanks
Answers.UserDisplayName: Christian Steger
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-01-19T21:15:09.180Z
Answers.Text: 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?
Answers.UserDisplayName: Tom De Smet
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-02-24T23:27:00.880Z
Answers.Text: @TomDeSmet Please have a look at my new answer. It solves your problem.
Answers.UserDisplayName: Christian Steger
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-08-23T16:14:12.597Z
Answers.LastActivityDate: 2014-08-25T16:12:58.090Z
Answers.LastEditDate: 2014-08-25T16:12:58.090Z
Answers.UserDisplayName: Brandon Kelly
Body: <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>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2018-04-18T10:31:05.417Z
Comments.Text: 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?
Comments.UserDisplayName: Tobias S.
Tags: <redirect>
Title: 302 redirects to locales in main index.php
ThreadText: # 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:
  
  ```php
  // 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](http://buildwithcraft.com/help/remove-index.php), 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()](http://buildwithcraft.com/classreference/services/HttpRequestService#getBrowserLanguages-detail) 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:
  
  ```php
  <?php
  
  // Make sure this isn't a CP request
  if (!isset($_GET['p']) || strncmp($_GET['p'], 'admin', 5) !== 0)
  {
      // Language paths
      $paths = array(
          'de' => '/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**: @username_4 Please have a look at my new answer. It solves your problem.  
  
  ---
  
  