Profruit banner

Умен звънец в openHAB

16 декември 2023

Телефонът е винаги с мен и сега, където и да се намирам получавам известие от openHAB, че някой е позвънил и чака пред вратата. А ако ме няма вкъщи става ясно часа и датата на последното позвъняване.

Tasmota Multipress

30 септември 2023

Идеята е Sonoff Touch T1 US 2 в салона, да управлява освен своето осветление и това в кухнята, а още вентилатора.

DIY 12V 1A WiFi Router UPS

22 април 2023

При поредно прекъсване на захранването вкъщи, батерията на нoтбука и двата UPS автоматично превключват на аварийно захранване и едновременно полита съобщение за конфуза

Zigbee2MQTT клониране

21 януари 2023

... как да клонираме съществуваща настройка на Zigbee2MQTT без да се налага последвало интервю на zigbee-устройствата.

LD2410 - бюджетен датчик присъствие в openHAB

11 февруари 2023

Цената на HLK-LD2410 зададе име на поредната тема в моя блог. С негова помощ се постига "народен" датчик присъствие в домашната автоматизация. . ...


От заглавието на темата следва, че показания скрипт е PHP форма за авторизация с възможност за запомняне. Този скрипт е изцяло моя разработка и го поднасям в качеството на подарък към настъпващата нова 2012 година.

Направата на сайт визитка, чрез когото рекламирате вашата дейност в интернет рано или късно води до нужда от администраторска зона. В този зона авторизиран потребител ще редактира съдържанието на сайта в зависимост от належащи промени. Съгласете се без тази зона, нещата изискват сайта да бъде изтеглян от хоста, редактиран и пак качван. Неудобно и непрактично. В такъв случай изплува потребност от зона само за правоимащи.


LMFAO - Sexy and I Know It

В тази зона ще влиза потребител, чиито парола и потребителско име съвпада с такива от база данни. При неактивност в течение на 24мин, той ще бъде изхвърлян от сесията. При желание потребителят ще има възможност, да бъде запомнян за една седмица напред, така че при следващ заход на адреса на админ зоната да влиза директно.

Началото изисква наличие на Login-формата. Виртуалното пространство предлага изобилие от решения.
Ако владеете графичен редактор и желаете индивидуалност този ресурс ще ви покаже стъпка по стъпка как да постигнете такава. Моето внимание задържа готово решение на Red. Направих леки козметични промени и нещата придобиха следния вид.

Mozila Firefox Windows XP

IE8 Windows XP

Разликите в интерпретиране на двата браузъра са очевадни. IE8 не владее CSS3, а това е идеята й в дизайна. Минимум Photoshop, максимум иновации.

При бъдещо разрастване на сайта е възможно да се добави нов бутон "Регистрация". На практика това ще извежда още едно поле - повтори паролата, било то с jQuery или само на CSS.

CSS


Стиловото оформление е поместено в спойлера. Slice-картинката (login-sprite.png) може да изтеглите от страницата на автора упомената горе. Без нея няма да се показват пиктограмите в полета за въвеждане на име и на парола.
spoiler :
/* 
    Document   : style
    Created on : Dec 2, 2011, 6:50:37 PM
    Author     : profruit
    Description: admin zone login form
*/

html, body
{
    height: 100%;    
    margin: 0;
    padding:0;
}

body
{
    font: 13px 'Lucida Sans Unicode', 'Trebuchet MS', Arial, Helvetica;    
    background-color: #d9dee2;
    background-image: -webkit-gradient(linear, left top, left bottom, from(#ebeef2), to(#d9dee2));
    background-image: -webkit-linear-gradient(top, #ebeef2, #d9dee2);
    background-image: -moz-linear-gradient(top, #ebeef2, #d9dee2);
    background-image: -ms-linear-gradient(top, #ebeef2, #d9dee2);
    background-image: -o-linear-gradient(top, #ebeef2, #d9dee2);
    background-image: linear-gradient(top, #ebeef2, #d9dee2);    
}

body:before
{
   content: "";
   position: fixed;
   top: -10px;
   left: 0;
   width: 100%;
   height: 10px;
   z-index: 100;
   -webkit-box-shadow: 0 0 22px rgba(11,11,11,.8);
   -moz-box-shadow: 0 0 22px rgba(11,11,11,.8);
   box-shadow: 0 0 22px rgba(11,11,11,.8);     
}

#login
{
    background-color: #fff;
    background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#eee));
    background-image: -webkit-linear-gradient(top, #fff, #eee);
    background-image: -moz-linear-gradient(top, #fff, #eee);
    background-image: -ms-linear-gradient(top, #fff, #eee);
    background-image: -o-linear-gradient(top, #fff, #eee);
    background-image: linear-gradient(top, #fff, #eee);  
    height: 240px;
    width: 400px;
    margin: -150px 0 0 -230px;
    padding: 30px;
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 0;
    -moz-border-radius: 3px;
    -webkit-border-radius: 3px;
    border-radius: 3px;  
    -webkit-box-shadow: 0 4px 18px #C8C8C8;
    -moz-box-shadow: 0 4px 18px #C8C8C8;
    box-shadow: 0 14px 38px grey;
}

#login:before
{
    content: "";
    position: absolute;
    z-index: -1;
    border: 1px dashed #ccc;
    top: 5px;
    bottom: 5px;
    left: 5px;
    right: 5px;
    -moz-box-shadow: 0 0 0 1px #fff;
    -webkit-box-shadow: 0 0 0 1px #fff;
    box-shadow: 0 0 10px 1px rgba(247, 251, 252, 1);

}

h1
{
    text-shadow: 0 1px 4px rgba(247, 251, 252, .7), 1px 1px 4px rgba(0, 0, 0, .4);
    text-transform: uppercase;
    text-align: center;
    color: #666;
    margin: 0 0 30px 0;
    letter-spacing: 4px;
    font: normal 26px/1 Verdana, Helvetica;
    position: relative;
}

h1:after, h1:before
{
    background-color: #777;
    content: "";
    height: 1px;
    position: absolute;
    top: 15px;
    width: 120px;   
}

h1:after
{ 
    background-image: -webkit-gradient(linear, left top, right top, from(#777), to(#fff));
    background-image: -webkit-linear-gradient(left, #777, #fff);
    background-image: -moz-linear-gradient(left, #777, #fff);
    background-image: -ms-linear-gradient(left, #777, #fff);
    background-image: -o-linear-gradient(left, #777, #fff);
    background-image: linear-gradient(left, #777, #fff);      
    right: 0;
}

h1:before
{
    background-image: -webkit-gradient(linear, right top, left top, from(#777), to(#fff));
    background-image: -webkit-linear-gradient(right, #777, #fff);
    background-image: -moz-linear-gradient(right, #777, #fff);
    background-image: -ms-linear-gradient(right, #777, #fff);
    background-image: -o-linear-gradient(right, #777, #fff);
    background-image: linear-gradient(right, #777, #fff);
    left: 0;
}


fieldset
{
    border: 0;
    padding: 0;
    margin: 0;
}

#inputs input
{
    background: #f1f1f1 url('login-sprite.png') no-repeat;
    padding: 15px 15px 15px 30px;
    margin: 0 0 10px 0;
    width: 353px; /* 353 + 2 + 45 = 400 */
    border: 1px solid #ccc;
    -moz-border-radius: 5px;
    -webkit-border-radius: 5px;
    border-radius: 5px;
    -moz-box-shadow: 0 1px 1px #ccc inset, 0 1px 0 #fff;
    -webkit-box-shadow: 0 1px 1px #ccc inset, 0 1px 0 #fff;
    box-shadow: 0 1px 1px #ccc inset, 0 1px 0 #fff;
}

#username
{
    background-position: 8px 0 !important;
    font: normal 17px Helvetica;
    color: grey;
}

#password
{
    background-position: 8px -50px !important;
    font: normal 17px Helvetica;
    color: grey !important;
}

#inputs input:focus
{
    background-color:rgb(253, 253, 253);
    border-color: #e8c291;
    outline: none;
    -moz-box-shadow: 0 0 0 1px #e8c291 inset;
    -webkit-box-shadow: 0 0 0 1px #e8c291 inset;
    box-shadow: 0 0 0 1px #e8c291 inset;
}

#actions
{
    margin: 25px 0 0 0;
}

#submit
{  
    background-color: #ffb94b;
    background-image: -webkit-gradient(linear, left top, left bottom, from(#fddb6f), to(#ffb94b));
    background-image: -webkit-linear-gradient(top, #fddb6f, #ffb94b);
    background-image: -moz-linear-gradient(top, #fddb6f, #ffb94b);
    background-image: -ms-linear-gradient(top, #fddb6f, #ffb94b);
    background-image: -o-linear-gradient(top, #fddb6f, #ffb94b);
    background-image: linear-gradient(top, #fddb6f, #ffb94b);
    
    -moz-border-radius: 3px;
    -webkit-border-radius: 3px;
    border-radius: 3px;
    
    text-shadow: 0 1px 0 rgba(255,255,255,0.5);
    
     -moz-box-shadow: 0 0 1px rgba(0, 0, 0, 0.3), 0 1px 0 rgba(255, 255, 255, 0.3) inset;
     -webkit-box-shadow: 0 0 1px rgba(0, 0, 0, 0.3), 0 1px 0 rgba(255, 255, 255, 0.3) inset;
     box-shadow: 0 0 1px rgba(0, 0, 0, 0.3), 0 1px 0 rgba(255, 255, 255, 0.3) inset;    
    
    border-width: 1px;
    border-style: solid;
    border-color: #d69e31 #e3a037 #d5982d #e3a037;

    float: left;
    height: 35px;
    padding: 0;
    width: 120px;
    cursor: pointer;
    font: bold 15px Arial, Helvetica;
    color: #8f5a0a;
}

#submit:hover,#submit:focus
{  
    background-color: #fddb6f;
    background-image: -webkit-gradient(linear, left top, left bottom, from(#ffb94b), to(#fddb6f));
    background-image: -webkit-linear-gradient(top, #ffb94b, #fddb6f);
    background-image: -moz-linear-gradient(top, #ffb94b, #fddb6f);
    background-image: -ms-linear-gradient(top, #ffb94b, #fddb6f);
    background-image: -o-linear-gradient(top, #ffb94b, #fddb6f);
    background-image: linear-gradient(top, #ffb94b, #fddb6f);
} 

#submit:active
{  
    outline: none;
   
     -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5) inset;
     -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5) inset;
     box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5) inset;  
}

#submit::-moz-focus-inner
{
  border: none;
}

#login label
{
    color: #3151A2;    
    float: right;
    padding-top: 10px;
    margin-right: 80px;
    font: bold 15px Arial, Helvetica;
    cursor: pointer;
}

HTML конструкция на формата


Формата e пoстроена на HTML5, а документа й носи гордо име index.php. Въведените данни ще предава на файл processor.php. В началото ще се включва файл checkpoint.php.

<?php 
    defined('CHECK_POINT') ? null : define("CHECK_POINT", true);
    include 'checkpoint.php';
?>
<!DOCTYPE html>
<html>
    <head>
 <link  href="style.css" rel="stylesheet" type="text/css">
 <meta content="noindex, nofollow" name="robots">
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Admin zone</title>
    </head>
    <body>
 
 <!-- Login Form -->
<form id="login" method="post" action="processor.php">
    <h1>Admin</h1>
    <fieldset id="inputs">
        <input id="username" type="text" name="username" value="<?=$_SESSION['error'] ?>" placeholder="Username" maxlength="32">   
        <input id="password" type="password" name="password" placeholder="Password" maxlength="32">
    </fieldset>
    <fieldset id="actions">
        <input type="submit" id="submit" name="submit" value="Log in">
        <label><input name="rememberMe" type="checkbox" id="rememberme" checked="checked" value="1">Remember Me</label>
 <input type="hidden" name="openSesame" value="<?= $key ?>">
    </fieldset>
</form>
    </body>
</html>
<?php $_SESSION['error']=null; ?>

Реших всички служебни съобщения на системата да се показват в полето за въвеждане на потребителско име. Неправилно въведено име или парола, име по-кратко от три символа и т.н. По този начин си спестявам допълнителни манипулации около дизайна на формата. Сесионна променлива error ще извежда тези съобщения на потребителя. На практика това е вход само за собственика на сайта, но тук може да се очаква всеки един, така че максимални мерки за сигурност.

При три поредни неправилни въвеждания на данните ще се извежда предупреждение "три поредни опита за вход". Събитието ще бъде регистрирано в лог файл, достъп до когото ще има само админа. В този файл ще се записва IP-то, браузъра, дата и часа на опита за вход.

Нещо много важно и на вид може да изглежда претрупано от код. Искам тази форма да бъде изпратена от този адрес, от това IP, от този браузър. Към този сбор от информация добавям случайно генерирано число и накрая хешираm чрез md5(). Хеша ($key) предавам като стойност на скрито поле и го очаквам от другата страна на processor.php. По този начин режа ботове и всякакви шмекерии.

checkpoint.php


Това е първия PHP файл. Той се зарежда в началото на формата. Статична променлива CHECK_POINT го пази от директен достъп.

<?php
if(!defined('CHECK_POINT')) // пряк достъп до файла забранен
{
    header('Location: index.php');
    exit;
}
else
{
    session_start();

    if($_SESSION['loggedin']===true)
 {
     header('Location: dashboard.php'); //вход в админ панел
     exit;
 }
    else if(isset($_COOKIE['prologin']))
 {
     $token = addslashes($_COOKIE['prologin']); //извличаме значението от бисквитката

     require_once 'db.php'; //връзка с БД

     $sql = 'SELECT `login` FROM `users` WHERE `token` ="'.$token.'"';
     $res = mysql_query($sql, $id); //изпълняваме заявката

     if(mysql_num_rows($res)==1) // точно попадение и login
     {
  $token = md5(time());
  $row = mysql_fetch_assoc($res); //извличаме потребителските данни
  $_SESSION['loggedin'] = true; // ключът от Рая
  $_SESSION['user_info'] = $row; //прехвърляме инфото в сесия

  unset($_COOKIE['prologin']); // удължаваме живота на бисквитките
  setcookie("prologin", $token, time()+60*60*24*7);
  mysql_query('UPDATE `base_name`.`users` SET `token`= "'.$token.'" WHERE login="'.$row['login'].'"', $id);
  close_connection();

  header('Location: dashboard.php');
  exit;
     }
     else if(mysql_num_rows($res)==0) // убиваме заблудените бисквитки
     {
  setcookie("prologin", null, time()-3600);

  header('Location: index.php');
  exit();
     }
 }
    else
 {
     $_SESSION['rand'] = rand(0, 9999);// id на формата
     $key = md5($_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_HOST'].$_SERVER['HTTP_USER_AGENT'].$_SESSION['rand']); 
     //хеш за value на hidden input
 }
}

Логиката на сайта, движена от PHP, ще следи потребителя. Ако е логнат, формата се крие и се пренасочва към авторизираната зона за редактиране съдържанието на страниците на сайта, която нарекох dashboard.php. На там и насочвам логнатия.

Търсим първо сесия. Ключ -значение е $_SESSION['loggedin']===true.Ако липсва, търсим бисквитка от $_COOKIE.

При наличие на $_COOKIE['prologin'] извличам съдържанието й и го предавам за анализ. Бисквитката нарекох жетон. Жетон има едноименно поле в базата данни. При съвпадение на значенията настъпва ОК. Съдържанието на този жетон е хеширано юникс-щамп време. Времето е променлива величина и тя не се повтаря. Убивам бисквитката и я създавам отново с нов хеш. Паралелно обновявам хеша в базата данни за последвало сравнение. Това удостоверение прехвърлям на сесия и продължавам към админ-зонaта (dashboard.php).

Ако липсва бисквитка, показваме формата за съответни действия. В края на файла се генерира число, нужно за хеша на скритото поле ($key).

processor.php


Този файл обработва постъпващите данни от формата.

<?php
session_start(); //сесия старт

defined('CHECK_POINT') ? null : define("CHECK_POINT", true);
require 'db.php'; 
//db.php добавен само ако CHECK_POINT е defined

$key = md5($_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_HOST'].$_SERVER['HTTP_USER_AGENT'].$_SESSION['rand']); 
//очакваме същия ключ от формата

if($_POST['openSesame'] == $key && $_POST['submit']=='Log in') // form submited
{
    $username = $_POST['username']; //прием на данните от формата 
    $username = mb_substr($username, 0, 32, 'utf-8'); //отсича израз дълъг над 32 символа
    $username = trim($username); //маха пробелите
    $username = mb_strtolower($username, 'utf-8'); //преход в долен регистър на символите
    $username = addslashes($username);//екранира ('),("),(\),(NULL) и magic_quotes_gpc = off
    
    $password = $_POST['password'];
    $password = mb_substr($password, 0, 32, 'utf-8');
    $password = md5(trim($_POST['password']));
    
    $rememberMe = (int)$_POST['rememberMe']; //стойност от checkbox
    $_SESSION['error'] = array(); //масив за служебни съобщения
    
    $pattern='/script|http|<|>|%3c|%3e|SELECT|UNION|UPDATE|INSERT|AND|OR|--|=|!|exe|exec|users/i'; //шаблон
    if (preg_match($pattern, $username)) //никакъв sql допустим отвън 
    {
 $_SESSION['error']='ползване на спец знаци забранено';
 header('Location: index.php');
 exit;
    }
    else
    {
 if(strlen($username)>2 && strlen($password)>2) //валидация на данните 
 {
     $sql = 'SELECT * FROM `base_name`.`users` WHERE `login`="'.$username.'" AND pass="'.$password.'"'; // (*) според случая
     $res = mysql_query($sql, $id);
     unset($sql);

     if(mysql_num_rows($res)==1) //точно попадение и login
     {
  $row = mysql_fetch_assoc($res); //извличаме потребителските данни
  $_SESSION['loggedin'] = true; //ключ към забранената зона
  $_SESSION['user_info'] = $row;

  if($rememberMe == 1)
  {
      $token = md5(time()); // бисквитка запомни ме
      setcookie("prologin", $token, time()+60*60*24*7); //една седмица живот
      mysql_query('UPDATE `base_name`.`users` SET `token`= "'.$token.'" WHERE login="'.$username.'"', $id);
      close_connection();
  }

  header('Location: dashboard.php');
  exit;
     }
     elseif(mysql_num_rows($res)==0) // без попадение
     {
  if(!isset($_SESSION['try'])) $_SESSION['try']=0;
  $_SESSION['try']+=1;

  if($_SESSION['try']>=3)
  {
      $log = './logs/log.txt';
      $data = 'IP = '.$_SERVER['REMOTE_ADDR'].' Agent = '.$_SERVER['HTTP_USER_AGENT'].' Date = '.date("r", time());
      file_put_contents($log, $data."\n", FILE_APPEND);//регистрация на неуспешен вход
      
      $_SESSION['warning'] = true;//ключ към warning.php
      $_SESSION['error']='три поредни опита за вход';
      $_SESSION['try'] = null;
      
      header('Location: warning.php');
      exit;
  }
  else
  {
      $_SESSION['error']='грешно име или парола';
      header('Location: index.php');
      exit;
  }
     }
     elseif(mysql_num_rows($res)>1) // ненормален резултат
     {
  //hacking attemp!
  // запис в log-файл или мейл-известие
     }
     }
     else
     {
  //име и/или парола по-малко от 3 символа
  $_SESSION['error']='по-малко от 3 символа въведени';
  header('Location: index.php');
  exit;
     }
    }  
}
else
{
    //опит за директен достъп до processor.php. Марш назад!
    header('Location: index.php');
    exit;
}

Нещата се повтарят и преминавам към новите. В ред 14-ти филтрирам през функция mb_substr(). Тъпо е някой да излее копие на Библията в полетата. Функция mb_strtolower() превежда символи от горен регистър в долен. В случай на разсеян админ. Функция addslashes() не ми е достатъчна и филтрирам през регулярен израз. Без SQL инжекции.

Ако checkbox е маркиран, генерирам бисквитка по споменатия горе механизъм. До края следват проверки и неуспеха им извеждам в полето на формата с съответни съобщения.

Променливата $_SESSION['try'] ще се отброява броя последователни опита за налучкване. След третия неуспешен записвам събитието в лог файл log.txt.

dashboard.php


Този документ е бъдещата зона на админа. Той тепърва ще се развива. Идеяата е да се покаже как работи скрипта. Първо проверяваме булевата стойност на loggedin. Този тригер казва Сезам отвори се или марш към формата.

<?php
    session_start();// проверка статуса на потребителя
    if($_SESSION['loggedin']!==true) 
    { 
 header('Location: index.php');
 exit();
    }
?>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Admin zone</title>
</head>
<body>
 <p>Welcome to the admin zone <strong><?=$_SESSION['user_info']['login'] ?></strong>. <a href="logout.php">Log out</a>.</p>

</body>
</html>

logout.php


Файлът за изход от системата. Убивам сесията и евентуално бисквитката. Логично пренасочване към индекса.

<?php
    // унищожение на бисквитките
    session_start();
    session_unset();
    session_destroy();

    if(isset($_COOKIE['prologin']))
    {
 setcookie("prologin", null, time()-3600);
    }

    header('Location: index.php');
    exit();

warning.php


Този файл пренасочва потребителя след три поредни неуспешни опита за вход и извежда подобаващо съобщение. Ясно, че стилизацията му е наложителна.

<?php
    session_start();
    if($_SESSION['warning']!==true) 
    { 
 header('Location: index.php');
 exit();
    }
    else
    {
 unset($_SESSION['try'],$_SESSION['warning']);
    } 
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Warning zone</title>
</head>
<body>
 <p>Вие направихте три неуспешни опита за вход в системата.Вашите данни са рапортувани</p>
 <p><a href="index.php">Назад</a></p>
</body>
</html>

Лог файл


Следва интересна част. Къде става регистрацията на неуспешния опит и как се организира. За целта нека погледнем структурата на сайта.

Създавам каталог administrator и в него държа всички описани до тук файлове. Вътре създавам нов каталог logs, а в него текстови файл log.txt с права 0777.

admin zone

Достъпът до този файл трябва да бъде забранен. Прегледа на съдържанието в каталог logs също забранявам. Той ще бъде четен само по ftp достъп. На помощ идва файл .htaccess. С директиви забранявам четене съдържанието на директории, достъпа до log.txt.

Всеки подобен опит ще връща грешка 403 Forbidden. Този рапорт на Apache ще обработвам в error.php, като пренасочвам към индекса. Реших да прихващам и грешка 404. Тази грешка сървърът връща при некоректен адрес, тоест, обръщение към несъществуващ файл или каталог.

.htaccess


В коментарите съм добавил команди за активиране на htaccess в Ubuntu. Apache след първоначална инсталация не обработва htaccess. Променете None на All в AllowOverride All и рестартирайте сървъра. Това става в конфигурационния файл 000-default. Конзолата на помощ.

## Disable Listing in Debian systems
Options -Indexes
#
# sudo gedit /etc/apache2/sites-enabled/000-default
#Options Indexes FollowSymLinks MultiViews
#AllowOverride All

## Disable server signature
ServerSignature Off

## Disable file access
<Files ~ "^log\.txt">
Order allow,deny
Deny from all
</Files>

## redirect to home page
#Forbidden
ErrorDocument 403 /administrator/error.php

#Not Found
ErrorDocument 404 /administrator/error.php


error.php


Този документ обработва резултата върнат от глобална променлива $_SERVER['REDIRECT_STATUS'].

<?php
/* обработваме грешки и пренасочваме към индекса*/
if(isset($_SERVER['REDIRECT_STATUS']));
{
    $status = $_SERVER['REDIRECT_STATUS'];
    
    //403 забранен
    //404 не намерен
    
    if($status==403 || $status==404)
    {
 header('Location: /administrator/index.php');//твърдо зададен абсолютен път до желан документ
 exit;
    }
}

Тънкия момент е да стиковате правилните абсолютни пътища. При опит за директен прочит на log.txt през браузъра, сървърът ще връща код 403, а PHP ще го прихваща и обработва. Съответно пренасочва към избрано място от сайта. Ако има разминаване ще се получи зацикляне (верижна реакция) или просто плюване на името на директорията от Apache в браузъра.


db.php


Този файл организира връзката ни с базата данни. В съответните редове поставете вашите значения за потребител, парола и име на база данни.

<?php

if(!defined('CHECK_POINT')) // пряк достъп до файла забранен
{
    header('Location: index.php');
    exit;
}
else
{
    //DB константи

    /* MySQL hostname */
    defined('DB_HOST') ? null : define("DB_HOST", "localhost");

    /* MySQL database username */
    defined('DB_USER') ? null : define("DB_USER", "root_name");

    /* MySQL database password */
    defined('DB_PASS') ? null : define("DB_PASS", "password");

    /* The name of the database */
    defined('DB_NAME') ? null : define("DB_NAME", "base_name");

    //съединение с MySQL
     $id=mysql_connect(DB_HOST, DB_USER, DB_PASS) or die('No server connected');

    //избор база данни
     mysql_select_db(DB_NAME, $id) or die('No DB selected');

    //хак на енкодинга
     mysql_query('SET CHARACTER SET utf8', $id); 
     // mysql_query('SET names utf8', $id);

     //mysql_close($id);
     function close_connection()
     {
  global $id;
  if(isset($id))
     {
  mysql_close($id);
  unset($id);
     }
     }
}

SQL


Създайте база данни и импортирайте тази SQL заявка. Работете в utf8_general_ci.

CREATE TABLE IF NOT EXISTS `users` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT,
  `login` varchar(32) NOT NULL,
  `pass` varchar(32) NOT NULL,
  `date_registred` int(11) NOT NULL,
  `token` varchar(32) NOT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;


Идеи за повече безопасност


На реален хост вдигаме флаг httponly = TRUE.
По този начин забраняваме достъпа на JS, да чете бисквитки, а тях задаваме така:
setcookie("prologin", $token, time()+60*60*24*7, "/admin/", "example.com", false, true);

dashboard.php е закритата зона на сайта и тя е само за логнати. $_SESSION['warning'] е ключа към закритата зона и само ще спечелим, ако добавим "отпечатък". Това е променлива, която записва информация от потребителя. Например, HTTP_USER_AGENT, IP и т.н. Отново хешираме, след което присвояваме на променлива от $_SESSION. Например:

$fingerprint = sha1($_SERVER['HTTP_USER_AGENT']);
$_SESSION['fingerprint'] = $fingerprint;


От този момент освен $_SESSION['warning'] следим и $_SESSION['fingerprint']. Ако всичко е гуд - пускаме, ако не назад моме Калино.

"Запомни ме" обаче се явява ахилесова пета на скрипта. Бисквитката може да бъде открадната. След което редактирана в браузър Opera (най-лесния начин).


Скриптът е изпробван на платформа Xampp 1.7.3 Windows XP SP3 и Ubuntu 10.04.
Възможно е под xampp/wamp да имa фал-старт. Тази версия при мен не чете съкратен начин на echo.

Ще бъда благодарен за всякакви критики, отзиви и препоръки.

Благодаря за вниманието и весели празници!






до нови срещи   ^.^

17.12.2011 profruit 

|

2 Response to "PHP Login Форма с Запомни ме"

  1. зайче Said,

    Весело посрещане на поредните ти празници XD
    http://www.youtube.com/watch?v=h0D6i2lQEtI&feature=endscreen&NR=1

     

  2. Marlou Said,

    Ако имам въпроси, мога ли да питам?

     

Публикуване на коментар

Този блог е реинкарнация на първите ми опити за споделяне в нета. На времето започнах с къси разкази на преживяното. После се обезсмисли и превърнах блога си в системно радио. Пиша единствено неща, които карат душата ми да живее: openHAB, Ubuntu, Споделено и т.н. Това е моето системно радио, разбирате ли? Моята вълна и вие сте на нея сега.

Архив на блога