Hej.

Założenie jest aby nie używać baz danych.

Funkcjonalności:
* Logowanie jako użytkownik + hasło lub samo hasło
* Max. próba logowań (bazowano na IP logującego)
* Prostota? (do waszej oceny)
* Bezpieczeństwo? (do waszej oceny)
* questionmark.gif


Dzięki!

PS: Tak, styl forma jest zerżnięty z Githuba, proszę już mnie za to nie karcić.

edit: dodałem komentarze ohno-smiley.gif

Usage
  1. <?
  2. require_once('authPage.php');
  3.  
  4. echo 'Logged in!';
  5. ?>



authPage.php
  1. <?
  2. /*
  3.  
  4. Config BEGIN
  5.  
  6. username => password
  7. username should contain alphameric chars only
  8.  
  9. */
  10.  
  11. $DATA = array(
  12. 'admin' => 'password',
  13. 'user' => 'qwert123',
  14. );
  15.  
  16.  
  17. define('USERNAMES', true); // Choose between using Username or Username + Password auth (true/false)
  18. define('TIMEOUT', 30); // How long user should stay logged in (set 0 for unlimited time) [in minutes]
  19. define('BANTIME', 15); // How long should IP ban after X fail login attempts last [in minutes]
  20. define('MAX_ATTEMPTS', 5); // Max. number of fail login attempts (int > 0)
  21.  
  22.  
  23. /*
  24.  
  25. Cofnig END
  26. Do NOT edit code below (unless you know what you are doing)
  27.  
  28. */
  29.  
  30.  
  31.  
  32. $Timeout = TIMEOUT == 0 ? pow(999, 3) : TIMEOUT * 60;
  33. $Bantime = BANTIME * 60;
  34. $RemoteIP = $_SERVER['REMOTE_ADDR'];
  35.  
  36. // Retrieve file name
  37. $FilePath = $_SERVER['SCRIPT_NAME'];
  38. $Break = Explode('/', $FilePath);
  39. $File = $Break[count($Break) - 1];
  40.  
  41. if( isset($_GET['logout']) ) {
  42.  
  43. $_SESSION['SLS_LOGGED'] = false;
  44.  
  45. header( 'Location: ' . $File );
  46.  
  47. die( );
  48.  
  49. }
  50.  
  51. // Check if max fail login attempts is 1 or greater
  52. if( MAX_ATTEMPTS < 1 )
  53. die('Max attempts must be 1 or grater!');
  54.  
  55. // Form submit
  56. if ( isset($_POST['commit']) )
  57. {
  58.  
  59. $Login = USERNAMES ? strtolower(trim($_POST['access_login'])) : '';
  60. $Password = $_POST['access_password'];
  61.  
  62. $LeftAttempts = 0;
  63.  
  64. // Load ban XML
  65. $DOM = new DOMDocument();
  66. $DOM->load('authPage.xml');
  67. $Attempts = $DOM->getElementsByTagName('attempt');
  68. $Found = false;
  69. $FoundAttempt = NULL;
  70.  
  71.  
  72. foreach( $Attempts as $Attempt )
  73. {
  74. // Check if IP already exists in XML [ref 01]
  75. if( $Attempt->getElementsByTagName('Remoteip')->item(0)->getAttribute('val') == $RemoteIP );
  76. {
  77. $Found = true;
  78. $FoundAttempt = $Attempt;
  79.  
  80. // Check if IP is already banned
  81. if ( $FoundAttempt->getElementsByTagName('Banned')->item(0)->getAttribute('val') == '1' )
  82. {
  83.  
  84. // Check if bantime already passed
  85. $TimePassed = time( ) - $FoundAttempt->getElementsByTagName('Timestamp')->item(0)->getAttribute('val');
  86.  
  87. if ( $TimePassed > $Bantime )
  88. {
  89. // It did, therefore remove the ban and continue executing
  90. removeBans($FoundAttempt);
  91. }
  92. else
  93. {
  94. // It didn't, show Login form with banned message and terminate
  95. showLoginPasswordProtect('Banned.');
  96. die( );
  97. }
  98. }
  99. }
  100. }
  101.  
  102. // If IP wasn't found in XML, create an entry and store first login attempt [ref 02]
  103. if( !$Found )
  104. {
  105. $_MainNode = $DOM->createElement('attempt');
  106. $DOM->getElementsByTagName('attempts')->item(0)->appendChild($_MainNode);
  107.  
  108. $_Remoteip = $_MainNode->appendChild( $DOM->createElement( 'Remoteip' ) );
  109. $_Remoteip->setAttribute('val', $RemoteIP);
  110.  
  111. $_Attempts = $_MainNode->appendChild( $DOM->createElement( 'Attempts' ) );
  112. $_Attempts->setAttribute('val', '1');
  113.  
  114. $_Banned = $_MainNode->appendChild( $DOM->createElement( 'Banned' ) );
  115. $_Banned->setAttribute('val', '0');
  116.  
  117. $_Timestamp = $_MainNode->appendChild( $DOM->createElement( 'Timestamp' ) );
  118. $_Timestamp->setAttribute('val', '0');
  119.  
  120. $LeftAttempts = MAX_ATTEMPTS - 1;
  121.  
  122. $DOM->save('authPage.xml');
  123. }
  124.  
  125. // Login FAILED
  126. if ( !USERNAMES && !in_array($Password, $DATA) || ( USERNAMES && ( !array_key_exists(strtolower(trim($Login)), $DATA) || $DATA[strtolower(trim($Login))] != $Password ) ) )
  127. {
  128. // IP has been previously found [ref 01]
  129. if ( $Found )
  130. {
  131.  
  132. $AttempsCount = $FoundAttempt->getElementsByTagName('Attempts')->item(0)->getAttribute('val'); // Retrieve number of attempts
  133. $AttempsCount++; // Increase attempts count by one
  134.  
  135. // Check if number of attempts matches (or exceeds -- possible?) max number of fail login attempts...
  136. if( $AttempsCount < MAX_ATTEMPTS )
  137. {
  138. $LeftAttempts = MAX_ATTEMPTS - $AttempsCount; // Var to display left no of attempts
  139.  
  140. $FoundAttempt->getElementsByTagName('Attempts')->item(0)->removeAttribute('val');
  141. $FoundAttempt->getElementsByTagName('Attempts')->item(0)->setAttribute('val', $AttempsCount); // Change attempts no
  142.  
  143. showLoginPasswordProtect('Incorrect Login and/or Password. ' . $LeftAttempts . ' attempt(s) left' );
  144. }
  145. // If so, ban IP address
  146. else
  147. {
  148. $FoundAttempt->getElementsByTagName('Banned')->item(0)->removeAttribute('val');
  149. $FoundAttempt->getElementsByTagName('Banned')->item(0)->setAttribute('val', '1'); // Ban
  150.  
  151. $FoundAttempt->getElementsByTagName('Timestamp')->item(0)->removeAttribute('val');
  152. $FoundAttempt->getElementsByTagName('Timestamp')->item(0)->setAttribute('val', time()); // Timestamp when banned
  153.  
  154. showLoginPasswordProtect('Banned.');
  155. }
  156.  
  157. $DOM->save('authPage.xml');
  158.  
  159. }
  160. // Display login form (ip not found) [ref 02]
  161. else
  162. showLoginPasswordProtect('Incorrect Login and/or Password. ' . $LeftAttempts . ' attempt(s) left' );
  163.  
  164. die( ); // Terminate after fail login attempt
  165.  
  166. }
  167. // Login success
  168. else
  169. {
  170.  
  171. removeBans($FoundAttempt); // Remove bancount/ban (if any)
  172. $DOM->save('authPage.xml');
  173.  
  174. $_SESSION['SLS_LOGGED'] = true; // Logged in
  175. $_SESSION['SLS_TIMEOUT'] = time( ) + $Timeout; // Timeout
  176.  
  177. unset($_POST); // Browser keep the post data anyway *dang*
  178.  
  179. header( 'Location: ' . $File ); // But we will force it to drop them!
  180.  
  181. die( ); // Always secured
  182.  
  183. }
  184.  
  185. }
  186. // No form has been submitted
  187. else
  188. {
  189. // Check if session expired.
  190. if( isset($_SESSION['SLS_TIMEOUT']) && time( ) > $_SESSION['SLS_TIMEOUT'] )
  191. {
  192. $_SESSION['SLS_LOGGED'] = false;
  193.  
  194. showLoginPasswordProtect('Session expired.');
  195.  
  196. die( );
  197. }
  198.  
  199. // Check if logged in
  200. if( !$_SESSION['SLS_LOGGED'] )
  201. {
  202. showLoginPasswordProtect('');
  203.  
  204. die( );
  205. }
  206.  
  207. // If logged in, keep session alive
  208. $_SESSION['SLS_TIMEOUT'] = time( ) + $Timeout;
  209.  
  210. }
  211.  
  212. // Display login form
  213. function showLoginPasswordProtect($error)
  214. {
  215.  
  216. ?>
  217. <html lang="en">
  218. <head>
  219.  
  220. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  221. <title>Login Panel</title>
  222. <link href="authPage.css" type="text/css" rel="stylesheet"/>
  223.  
  224. </head>
  225.  
  226. <body>
  227.  
  228. <div class="login_form" id="login">
  229.  
  230. <!-- Login form template `borrowed` from Github.com -->
  231.  
  232. <form method="post" action="<? print $GLOBALS['File'] ?>">
  233.  
  234. <h1>Log in</h1>
  235.  
  236. <div class="formbody">
  237.  
  238. <?
  239.  
  240. if( !empty($error) )
  241. print '<div class="error_box">' . $error . '</div>';
  242.  
  243. if ( USERNAMES )
  244. {
  245.  
  246. ?>
  247.  
  248. <label for="login_field">
  249.  
  250. Login<br />
  251.  
  252. <input type="text" tabindex="1" style="width: 21em;" name="access_login" id="login_field" class="text" autocapitalize="off">
  253.  
  254. </label>
  255.  
  256. <?
  257.  
  258. }
  259.  
  260. ?>
  261.  
  262. <label for="password">
  263.  
  264. Password<br />
  265.  
  266. <input type="password" value="" tabindex="2" style="width: 21em;" name="access_password" id="password" class="text" autocomplete="disabled">
  267.  
  268. </label>
  269.  
  270. <label class="submit_btn">
  271.  
  272. <input type="submit" value="Log in" tabindex="3" name="commit">
  273.  
  274. </label>
  275.  
  276. </div>
  277.  
  278. </form>
  279.  
  280. </div>
  281.  
  282. </body>
  283.  
  284. </html>
  285.  
  286. <?
  287.  
  288. }
  289.  
  290. // Remove bans function
  291. function removeBans($input)
  292. {
  293. $input->getElementsByTagName('Attempts')->item(0)->removeAttribute('val');
  294. $input->getElementsByTagName('Attempts')->item(0)->setAttribute('val', '0');
  295.  
  296. $input->getElementsByTagName('Banned')->item(0)->removeAttribute('val');
  297. $input->getElementsByTagName('Banned')->item(0)->setAttribute('val', '0');
  298.  
  299. $input->getElementsByTagName('Timestamp')->item(0)->removeAttribute('val');
  300. $input->getElementsByTagName('Timestamp')->item(0)->setAttribute('val', '0');
  301. }
  302.  
  303. ?>



authPage.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <attempts></attempts>



authPage.css
http://ideone.com/ZtPJl (nie zmieściło się do posta + mało istotne)


--- QUIT ---