title: Proper way to use "Remember me" functionality in PHP
body: <h1>Short</h1>
  <p>Working on login system and trying to implement remember me feature.</p>
  <p>Recently, l did research about this subject, read bunch of articles, posts, stories, novels, fairy tales (calling them so, because some of them doesn't contain even 1 line of code, just loads of words) about, cookie vulnerabilities such as fixation, hijacking ... etc.</p>
  <p>And decided to achieve following targets</p>
  <ol>
  <li>To set time delay between login attempts (to prevent bruteforce attacks) and to limit attempts count</li>
  <li>To regenerate session id on nearly every operation</li>
  </ol>
  <p><strong>But</strong> I really confused about my main problem: which way is proper, for &quot;remember me&quot; feature? to use cookies/session/database?</p>
  <p>And please explain your idea on code.(I can't understand clearly without code)</p>
  <h1>Detailed</h1>
  <p>Currently, my code looks like that</p>
  <p>During sign-in I'm using following function to set cookies and session</p>
  <pre><code>protected function validateUser($userid, $ckey=0, $rememmber=0) {
      session_start();
      session_regenerate_id(true); //this is a security measure
      $_SESSION['user_id'] = $userid;
      $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);
      if (isset($remember) &amp;&amp; $rememmber == 'on') {
          setcookie(&quot;user_id&quot;, $_SESSION['user_id'], time() + 60 * 60 * 24 * COOKIE_TIME_OUT, &quot;/&quot;);
          setcookie(&quot;user_key&quot;, sha1($ckey), time() + 60 * 60 * 24 * COOKIE_TIME_OUT, &quot;/&quot;);
      }
      return true;
  }
  </code></pre>
  <p>Then on secure user pages, checking for <code>user_id</code> using user_id to fetch all important data about user from db</p>
  <pre><code>public function protect() {
          session_start();
  
          /* Secure against Session Hijacking by checking user agent */
          if (isset($_SESSION['HTTP_USER_AGENT'])) {
              if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT'])) {
                  $this-&gt;signout();
                  exit;
              }
          }
  
  // before we allow sessions, we need to check authentication key - ckey and ctime stored in database
  
          /* If session not set, check for cookies set by Remember me */
          if (!isset($_SESSION['user_id'])) {
              if (isset($_COOKIE['user_id']) &amp;&amp; isset($_COOKIE['user_key'])) {
                  /* we double check cookie expiry time against stored in database */
  
                  $cookie_user_id = $_COOKIE['user_id'];
                                 $stmt = $this-&gt;db-&gt;prepare(&quot;select `ckey`,`ctime` from `users` where `id` =?&quot;) or die($this-&gt;db-&gt;error);
              $stmt-&gt;bind_param(&quot;i&quot;, $cookie_user_id) or die(htmlspecialchars($stmt-&gt;error));
              $stmt-&gt;execute() or die(htmlspecialchars($stmt-&gt;error));
              $stmt-&gt;bind_result($ckey, $ctime) or die($stmt-&gt;error);
              $stmt-&gt;close() or die(htmlspecialchars($stmt-&gt;error));
                  // coookie expiry
                  if ((time() - $ctime) &gt; 60 * 60 * 24 * COOKIE_TIME_OUT) {
                      $this-&gt;signout();
                  }
                  /* Security check with untrusted cookies - dont trust value stored in cookie.       
                    /* We also do authentication check of the `ckey` stored in cookie matches that stored in database during login */
  
                  if (!empty($ckey) &amp;&amp; is_numeric($_COOKIE['user_id']) &amp;&amp; $_COOKIE['key'] == sha1($ckey)) {
                      session_regenerate_id(); //against session fixation attacks.
  
                      $_SESSION['user_id'] = $_COOKIE['user_id'];
                      $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);
                  } else {
                      $this-&gt;signout();
                  }
              } else {
                  if ($page != 'main') {
                      header('Location:' . wsurl);
                      exit();
                  }
              }
          }
  </code></pre>