├── LICENSE ├── README.md ├── _compact └── htam-panel.php ├── _updates └── htam.json ├── index.php └── resources ├── core.php ├── dash.php ├── dir.php ├── style.css ├── updates.php └── users.php /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Mariano Sciacco 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/H2H6VK9N) 2 | 3 | # HTAccess Manager 4 | 5 | ![screenshot htam](https://i.imgur.com/U7Sz3LI.png) 6 | 7 | ### Description 8 | 9 | Manage password-protected directories and users accesses directly from a Web Panel. 10 | 11 | ### Requirements 12 | 13 | - Website with FTP access 14 | - PHP 7.x or superior 15 | - Permissions to read and write from a PHP script 16 | - Permission to use custom .htaccess 17 | 18 | ### Download 19 | 20 | Navigate under [Release](https://github.com/Maxelweb/HTAM/releases) and download the latest software named 21 | **htam-panel-compact-\*.zip** 22 | 23 | ### Installation 24 | 25 | This software is pretty simple to install. 26 | 27 | 1. Download ⬇ the compact version from the **Download** section above. 28 | 2. Unzip and put the `htam-panel.php` into the directory you want to protect. 29 | 3. Navigate to `yoursite.com/your-directory/htam-panel.php`. 30 | 4. Go to **Manage directory** and click **Create new .htaccess and/or .htpasswd file**. 31 | 5. Create a new user from **Manage users** and set it as **administrator** 32 | 6. Navigate to **Manage directory** and hit **Toggle directory protection** 33 | 7. Your directory is now protected! 😀 34 | 35 | > If you need, you can easily rename the .php file. You don't have to change any line of code. 36 | 37 | ### Features 38 | 39 | - Block access and add specific users to visit your online folder 40 | - Manage users with passwords and roles 41 | - Quickly enable or disable directory protection 42 | - Automatic creation and delete of the essential files (.htaccess, .htpasswd) 43 | - View current file and sub-directories protected by the script 44 | - Works with existing .htaccess file (it only appends / remove some particular lines to toggle the script) 45 | - Works both with Linux and Windows 46 | - 📱 Responsive lightweight design 47 | - ☕ Online updates checker 48 | - 😍 Built with Emoji! 49 | -------------------------------------------------------------------------------- /_compact/htam-panel.php: -------------------------------------------------------------------------------- 1 | currentDir = $dir; 65 | $this->htaFile = ".htaccess"; 66 | $this->htpFile = ".htpasswd"; 67 | } 68 | 69 | private function searchFor($file) 70 | { 71 | return file_exists($this->currentDir.DIRECTORY_SEPARATOR.$file); 72 | } 73 | 74 | private function getInside($string) 75 | { 76 | $pattern = "/\"(.*?)\"/"; 77 | preg_match_all($pattern, $string, $matches); 78 | if(!empty($matches[1][0])) 79 | return $matches[1][0]; 80 | return ""; 81 | } 82 | 83 | private function getFileContent($file) 84 | { 85 | if(!$this->searchFor($file)) 86 | return array(); 87 | return @file($this->currentDir.DIRECTORY_SEPARATOR.$file); 88 | } 89 | 90 | function hta() 91 | { 92 | return $this->currentDir.DIRECTORY_SEPARATOR.$this->htaFile; 93 | } 94 | 95 | function htp() 96 | { 97 | return $this->currentDir.DIRECTORY_SEPARATOR.$this->htpFile; 98 | } 99 | 100 | function dir() 101 | { 102 | return $this->currentDir; 103 | } 104 | 105 | function changeDir($newdir) 106 | { 107 | $this->currentDir = $newdir; 108 | } 109 | 110 | function hasHtaccess() 111 | { 112 | return $this->searchFor($this->htaFile); 113 | } 114 | 115 | function hasHtpasswd() 116 | { 117 | return $this->searchFor($this->htpFile); 118 | } 119 | 120 | function deleteHtaccess() 121 | { 122 | return unlink($this->hta()); 123 | } 124 | 125 | function deleteHtpasswd() 126 | { 127 | return @unlink($this->htp()); 128 | } 129 | 130 | function checkPermissions() 131 | { 132 | return is_readable($this->hta()) && 133 | is_readable($this->htp()) && 134 | is_writable($this->hta()) && 135 | is_writable($this->htp()); 136 | } 137 | 138 | function setPermissions() 139 | { 140 | return chmod($this->hta(), 644) && 141 | chmod($this->htp(), 644); 142 | } 143 | 144 | function createHtfiles() 145 | { 146 | if(!$this->hasHtaccess()) 147 | { 148 | $file = fopen($this->hta(), "w+"); 149 | if(!$file) 150 | return false; 151 | fclose($file); 152 | } 153 | 154 | if(!$this->hasHtpasswd()) 155 | { 156 | $file = fopen($this->htp(), "w+"); 157 | if(!$file) 158 | return false; 159 | fclose($file); 160 | } 161 | 162 | return true; 163 | } 164 | 165 | function icon() 166 | { 167 | return $this->isProtected() ? "🔒" : ""; 168 | } 169 | 170 | function getInfo() 171 | { 172 | $info = array("N/D", "N/D"); 173 | $lines = $this->getFileContent($this->htaFile); 174 | if(empty($lines)) 175 | return $info; 176 | 177 | foreach ($lines as $line) { 178 | if(preg_match("/AuthName/", $line)) 179 | $info[0] = $this->getInside($line); 180 | elseif(preg_match("/AuthUserFile/", $line)) 181 | $info[1] = $this->getInside($line); 182 | } 183 | 184 | return $info; 185 | } 186 | 187 | function isProtected() 188 | { 189 | if(!$this->hasHtaccess()) 190 | return false; 191 | 192 | $lines = $this->getFileContent($this->htaFile); 193 | if(empty($lines)) 194 | return false; 195 | $i = 0; 196 | while($i= count($lines)); 200 | } 201 | 202 | function addProtection() 203 | { 204 | if($this->isProtected()) 205 | return false; 206 | 207 | $fh = fopen($this->hta(), "a+"); 208 | if(!$fh) 209 | return false; 210 | $prot = "\n# HTAM - START \n# HTAccess Manager auto-generated script \nAuthType Basic \nAuthName \"Protected area\" \nAuthUserFile \"" . $this->htp() . "\"\nrequire valid-user \n# HTAM - END\n"; 211 | fwrite($fh, $prot); 212 | fclose($fh); 213 | return true; 214 | } 215 | 216 | function removeProtection() 217 | { 218 | $lines = $this->getFileContent($this->htaFile); 219 | if(empty($lines)) 220 | return false; 221 | 222 | $i = 0; 223 | while($i= count($lines)) 227 | return false; 228 | 229 | if($lines[$i-1] == "\n") 230 | unset($lines[$i-1]); 231 | 232 | for($j=$i; $j < $i+7; $j++) 233 | unset($lines[$j]); 234 | 235 | $cleaned = ""; 236 | foreach($lines as $line) 237 | $cleaned .= $line; 238 | 239 | $fh = fopen($this->hta(), "w+"); 240 | fwrite($fh, $cleaned); 241 | fclose($fh); 242 | 243 | return true; 244 | } 245 | 246 | function getUsers() 247 | { 248 | $users = array(); 249 | if(!$this->hasHtpasswd()) 250 | return $users; 251 | 252 | $lines = $this->getFileContent($this->htpFile); 253 | if(empty($lines)) 254 | return $users; 255 | 256 | foreach ($lines as $line) 257 | { 258 | $item = explode(":", $line); 259 | array_push($users, new HUser($item[0], $item[1], trim($item[2]))); 260 | } 261 | 262 | return $users; 263 | } 264 | 265 | function countAdmin() 266 | { 267 | $u = $this->getUsers(); 268 | $n = 0; 269 | if(!empty($u)) 270 | foreach ($u as $user) 271 | if($user->isAdmin()) 272 | $n++; 273 | 274 | return $n; 275 | } 276 | 277 | function findUser($name) 278 | { 279 | $u = $this->getUsers(); 280 | $i = 0; 281 | if(!empty($u)) 282 | while($iname() == $name) 285 | break; 286 | $i++; 287 | } 288 | 289 | if($i >= count($u)) 290 | return -1; 291 | 292 | return $i; 293 | } 294 | 295 | function changeUsers($users) 296 | { 297 | $checkOneAdmin = false; 298 | $cleaned = ""; 299 | $i = count($users); 300 | foreach($users as $user) 301 | { 302 | $cleaned .= $user->name().':'.$user->psw().':'.$user->isAdmin(); 303 | if($i-1 != 0) 304 | $cleaned .= "\n"; 305 | if(!$checkOneAdmin && $user->isAdmin()) 306 | $checkOneAdmin = true; 307 | $i--; 308 | } 309 | 310 | if(!$checkOneAdmin && $this->isProtected()) 311 | return false; 312 | 313 | 314 | $fh = fopen($this->htp(), "w+"); 315 | fwrite($fh, $cleaned); 316 | fclose($fh); 317 | return true; 318 | } 319 | 320 | function getSubDirFiles() 321 | { 322 | return array_diff(scandir($this->currentDir, 1), array('..', '.')); 323 | } 324 | } 325 | 326 | 327 | class HUser 328 | { 329 | private $username; 330 | private $password; 331 | private $admin; 332 | 333 | function __construct($n="none", $p="", $a=0) 334 | { 335 | $this->username = $n; 336 | $this->password = $p; 337 | $this->admin = $a; 338 | } 339 | 340 | public function name() 341 | { 342 | return $this->username; 343 | } 344 | 345 | public function psw() 346 | { 347 | return $this->password; 348 | } 349 | 350 | public function isAdmin() 351 | { 352 | return $this->admin; 353 | } 354 | 355 | public function changeUsername($name) 356 | { 357 | if(strlen($name) > 15 || strlen($name) < 3) 358 | return false; 359 | 360 | if(!preg_match("/^[a-zA-Z0-9\s_-]+$/", $name)) 361 | return false; 362 | 363 | $this->username = $name; 364 | return true; 365 | } 366 | 367 | public function changePassword($psw) 368 | { 369 | if(strlen($psw) > 32 || strlen($psw) < 4) 370 | return false; 371 | 372 | $pass = generatePassword($psw); 373 | 374 | $this->password = $pass; 375 | return true; 376 | } 377 | 378 | public function toggleAdmin($set) 379 | { 380 | $this->admin = $set ? 1 : 0; 381 | } 382 | } 383 | 384 | 385 | class HUpdates 386 | { 387 | private $version; 388 | private $payload; 389 | 390 | function __construct() 391 | { 392 | $this->version = VERSION; 393 | $this->payload = $this->checkNewVersion(); 394 | } 395 | 396 | private function checkNewVersion() 397 | { 398 | $json = file_get_contents('http://api.debug.ovh/htam.json'); 399 | if(!$json) 400 | return array(); 401 | 402 | return json_decode($json); 403 | } 404 | 405 | function currentVersion() 406 | { 407 | return $this->version; 408 | } 409 | 410 | function latestVersion() 411 | { 412 | if(!empty($this->payload)) 413 | return $this->payload->version; 414 | return "N/A"; 415 | } 416 | 417 | function info() 418 | { 419 | return $this->payload; 420 | } 421 | } 422 | 423 | 424 | function generatePassword($psw) 425 | { 426 | // Better than crypt() for portability 427 | return password_hash($psw, PASSWORD_BCRYPT); 428 | } 429 | 430 | function good($msg, $simple=0) 431 | { 432 | $cl = !$simple ? "good box" : "good"; 433 | return ''.$msg.''; 434 | } 435 | 436 | function bad($msg, $simple=0) 437 | { 438 | $cl = !$simple ? "bad box" : "bad"; 439 | return ''.$msg.''; 440 | } 441 | 442 | 443 | // ------------ Initialization and Authorization ------------ 444 | 445 | $htam = new htam(dirname(__FILE__)); 446 | 447 | if(isset($_SERVER['PHP_AUTH_USER'])) 448 | $findme = $htam->findUser($_SERVER['PHP_AUTH_USER']); 449 | else 450 | $findme = -1; 451 | 452 | $me = $findme > -1 ? $htam->getUsers()[$findme] : new HUser(); 453 | 454 | if($htam->isProtected() && !$me->isAdmin()) 455 | { 456 | echo "

HTAccess Manager

"; 457 | echo "

You logged in as a user. You must be an admin to access this page.

"; 458 | die(); 459 | } 460 | 461 | // --------------------------------- 462 | 463 | ?> 464 | 465 | 466 | 467 | HTAccess Manager 468 | 469 | 470 | 471 | 472 | 475 | 476 | 477 | 478 |
479 |

HTAccess Manager

480 | Current directory: dir();?> icon();?> 481 |
482 | 483 | 489 | 490 |
491 | 495 |
496 |

📁 Directory Management

497 | 498 | hasHtaccess() && $htam->hasHtpasswd() && !$htam->checkPermissions()) 501 | { 502 | echo bad("The .htaccess or .htpasswd files are not readable or writable. Set the correct permissions (664) from FTP or attempt to change permissions. "); 503 | } 504 | 505 | if($a == 1) 506 | { 507 | if(!$htam->isProtected()) 508 | { 509 | if(!$htam->hasHtaccess() || !$htam->hasHtpasswd() || $htam->countAdmin() == 0) 510 | { 511 | echo bad("Before enabling protection, you must create htaccess and htpasswd and add at least one administrator in Manage users."); 512 | } 513 | else 514 | { 515 | if($htam->addProtection()) 516 | echo good("Directory protection activated."); 517 | else 518 | echo bad("Error: unable to add directory protection. Check file permissions."); 519 | } 520 | } 521 | else 522 | { 523 | if($htam->removeProtection()) 524 | echo good("Directory protection removed."); 525 | else 526 | echo bad("Error: unable to remove directory protection. Check file permissions."); 527 | } 528 | } 529 | elseif($a == 3) 530 | { 531 | if($htam->createHtfiles()) 532 | echo good("Files created successfully."); 533 | else 534 | echo bad("Error: unable to create one or more files to initialize the script. Change manually write permissions for this folder."); 535 | } 536 | elseif($a == 4) 537 | { 538 | if($htam->isProtected()) 539 | echo bad("You must disable protection to delete Htaccess."); 540 | elseif($htam->deleteHtaccess()) 541 | echo good("Htaccess deleted successfully."); 542 | else 543 | echo bad("Error: unable to delete Htaccess."); 544 | } 545 | elseif($a == 5) 546 | { 547 | if($htam->isProtected()) 548 | echo bad("You must disable protection to delete Htpasswd."); 549 | elseif($htam->deleteHtpasswd()) 550 | echo good("Htpasswd deleted successfully."); 551 | else 552 | echo bad("Error: unable to delete Htpasswd."); 553 | } 554 | elseif($a == 6) 555 | { 556 | if($htam->setPermissions()) 557 | echo good("File permissions (664) applied successfully. Now the script is able to work properly."); 558 | else 559 | echo bad("Error: unable to set permissions (664). You must do it manually from FTP."); 560 | } 561 | 562 | ?> 563 |
564 | 565 |
566 |

Informations

567 | 568 |
    569 |
  • Directory protection: isProtected() ? good("Active",1) : bad("Disabled",1) ;?> 570 | [change] 571 |
  • 572 |
  • htaccess: hasHtaccess() ? good("Yes",1) : bad("No",1) ;?>
  • 573 |
  • htpasswd: hasHtpasswd() ? good("Yes",1) : bad("No",1) ;?>
  • 574 |
  • Area name: getInfo()[0];?> 575 |
  • htaccess location: hta();?> 576 |
  • htpasswd location: htp();?> 577 |
578 |
579 | 580 |
581 |

Options

582 | 583 | 587 | 588 | 597 | 598 | Protected files and directories [reload | close]"; 603 | $subs = $htam->getSubDirFiles(); 604 | if(empty($subs)) 605 | echo "None"; 606 | else 607 | { 608 | echo "
    "; 609 | foreach ($subs as $sub => $name) 610 | { 611 | if(is_dir($name)) 612 | echo "
  • 🔸 $name/
  • "; 613 | else 614 | echo "
  • 🔹 $name
  • "; 615 | } 616 | echo "
"; 617 | } 618 | } 619 | 620 | ?> 621 |
622 | 623 | 628 |
629 |

👥 User management

630 | 631 | getUsers(); 634 | $edit = isset($_GET['edit']) ? $_GET['edit'] : ""; 635 | 636 | if($a == 1) 637 | { 638 | $un = $_POST['uname']; 639 | $up = $_POST['upass']; 640 | $urp = $_POST['urpass']; 641 | 642 | $find = $htam->findUser($un); 643 | $user = $find > -1 ? $users[$find] : new HUser(); 644 | 645 | 646 | if(!$user->changeUsername($un)) 647 | { 648 | echo bad("The username must contain only alphanumeric characters, dash, underscore and spaces (from 3 to 15 characters long)."); 649 | } 650 | elseif(!$user->changePassword($up)) 651 | { 652 | echo bad("The password must be at least 4 characters and maximum 32 characters long."); 653 | } 654 | elseif($up != $urp) 655 | { 656 | echo bad("The password repeated is different."); 657 | } 658 | else 659 | { 660 | if($find > -1) 661 | $users[$find] = $user; 662 | else 663 | array_push($users, $user); 664 | 665 | 666 | if($htam->changeUsers($users)) 667 | echo good("User $un has been added/edited successfully.
668 | Username: $un - Password: $up"); 669 | else 670 | echo bad("Error: unable to update users file. Check permissions."); 671 | } 672 | } 673 | elseif($a == 2 && !empty($edit)) 674 | { 675 | $find = $htam->findUser($edit); 676 | $user = $find > -1 ? $users[$find] : ""; 677 | if(empty($user)) 678 | echo bad("The user selected has not been found."); 679 | elseif(isset($me) && $user->name() == $me->name() && $htam->isProtected()) 680 | echo bad("You can't delete yourself while directory protection is active."); 681 | else 682 | { 683 | unset($users[$find]); 684 | if($htam->changeUsers($users)) 685 | echo good("The user has been removed permanently."); 686 | else 687 | echo bad("Error: unable to update users file. Check permissions."); 688 | 689 | } 690 | } 691 | elseif($a == 3 && !empty($edit)) 692 | { 693 | $find = $htam->findUser($edit); 694 | $user = $find > -1 ? $users[$find] : ""; 695 | if(empty($user)) 696 | echo bad("The user selected has not been found."); 697 | elseif( ($htam->countAdmin() == 1 || (isset($me) && $user->name() == $me->name()) ) 698 | && $user->isAdmin() && $htam->isProtected()) 699 | echo bad("You can't remove the last administrator or yourself as administrator while protection is enabled."); 700 | else 701 | { 702 | $users[$find]->toggleAdmin($user->isAdmin() ? 0 : 1); 703 | if($htam->changeUsers($users)) 704 | echo good("The role of the user {$user->name()} has been changed."); 705 | else 706 | echo bad("Error: unable to update users file. Check permissions."); 707 | 708 | } 709 | } 710 | 711 | ?> 712 |
713 | 714 | 734 | 735 |
736 |

Add / edit user

737 |

If the username is already in use, the password will be overrided with the new one.

738 |
739 | 740 |
741 | 742 |
743 | 744 |
745 |
746 | 747 |
748 | 749 |

Users list

750 | 751 | Total users: ".count($users).", Administrators: ".$htam->countAdmin()." "; 757 | echo "
"; 758 | foreach ($users as $user) 759 | { 760 | echo ""; 761 | echo ""; 762 | echo ""; 763 | echo ""; 764 | if(!$user->isAdmin()) 765 | echo ""; 766 | else 767 | echo ""; 768 | echo ""; 769 | echo ""; 770 | } 771 | echo "
{$user->name()}".($user->isAdmin() ? bad("🤠 administrator",1) : good("😃 user",1))."edit passwordset adminset userdelete
"; 772 | } 773 | 774 | ?> 775 |
776 | 777 | 782 |
783 |

☕ Updates

784 | latestVersion() == "N/A") 788 | echo bad("Unable to check for new updates. Try later or checkout the official repository."); 789 | elseif($hup->currentVersion() != $hup->latestVersion()) 790 | echo bad("Your version is not up to date."); 791 | else 792 | echo good("Your version is up to date."); 793 | ?> 794 | 795 |

Updates checker

796 |
    797 |
  • Current version: currentVersion();?>
  • 798 |
  • Latest version: latestVersion();?>
  • 799 |
  • Github repository for updates:
  • 800 |
801 | 802 | info())) 804 | { 805 | echo "
"; 806 | foreach ($hup->info() as $key => $value) 807 | { 808 | echo " 809 | 810 | 811 | "; 812 | } 813 | echo "
$key$value
"; 814 | } 815 | ?> 816 | 817 |
818 | 819 | 824 | 825 | 826 |
827 |

🏠 Dashboard

828 | 829 |

Welcome to the HTAccess Manager. From here, you can manage users and directory protection.

830 | 831 |
    832 |
  • Directory protection: isProtected() ? good("Active",1) : bad("Disabled",1) ;?> 833 | [change] 834 |
  • 835 |
  • Current Login Username: name() : "None";?>
  • 836 |
  • Total users: getUsers() ? 0 : count($htam->getUsers());?>
  • 837 |
838 |
839 | 840 | 843 |
844 | 845 | 848 | 849 | 850 | -------------------------------------------------------------------------------- /_updates/htam.json: -------------------------------------------------------------------------------- 1 | { 2 | "version" : "0.1", 3 | "date" : "05-2019", 4 | "status" : "stable", 5 | "description" : "Initial release" 6 | } -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | findUser($_SERVER['PHP_AUTH_USER']); 63 | else 64 | $findme = -1; 65 | 66 | $me = $findme > -1 ? $htam->getUsers()[$findme] : new HUser(); 67 | 68 | if($htam->isProtected() && !$me->isAdmin()) 69 | { 70 | echo "

HTAccess Manager

"; 71 | echo "

You logged in as a user. You must be an admin to access this page.

"; 72 | die(); 73 | } 74 | 75 | // --------------------------------- 76 | 77 | ?> 78 | 79 | 80 | 81 | HTAccess Manager 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 |
91 |

HTAccess Manager

92 | Current directory: dir();?> icon();?> 93 |
94 | 95 | 101 | 102 |
103 | 113 |
114 | 115 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /resources/core.php: -------------------------------------------------------------------------------- 1 | currentDir = $dir; 13 | $this->htaFile = ".htaccess"; 14 | $this->htpFile = ".htpasswd"; 15 | } 16 | 17 | private function searchFor($file) 18 | { 19 | return file_exists($this->currentDir.DIRECTORY_SEPARATOR.$file); 20 | } 21 | 22 | private function getInside($string) 23 | { 24 | $pattern = "/\"(.*?)\"/"; 25 | preg_match_all($pattern, $string, $matches); 26 | if(!empty($matches[1][0])) 27 | return $matches[1][0]; 28 | return ""; 29 | } 30 | 31 | private function getFileContent($file) 32 | { 33 | if(!$this->searchFor($file)) 34 | return array(); 35 | return @file($this->currentDir.DIRECTORY_SEPARATOR.$file); 36 | } 37 | 38 | function hta() 39 | { 40 | return $this->currentDir.DIRECTORY_SEPARATOR.$this->htaFile; 41 | } 42 | 43 | function htp() 44 | { 45 | return $this->currentDir.DIRECTORY_SEPARATOR.$this->htpFile; 46 | } 47 | 48 | function dir() 49 | { 50 | return $this->currentDir; 51 | } 52 | 53 | function changeDir($newdir) 54 | { 55 | $this->currentDir = $newdir; 56 | } 57 | 58 | function hasHtaccess() 59 | { 60 | return $this->searchFor($this->htaFile); 61 | } 62 | 63 | function hasHtpasswd() 64 | { 65 | return $this->searchFor($this->htpFile); 66 | } 67 | 68 | function deleteHtaccess() 69 | { 70 | return unlink($this->hta()); 71 | } 72 | 73 | function deleteHtpasswd() 74 | { 75 | return @unlink($this->htp()); 76 | } 77 | 78 | function checkPermissions() 79 | { 80 | return is_readable($this->hta()) && 81 | is_readable($this->htp()) && 82 | is_writable($this->hta()) && 83 | is_writable($this->htp()); 84 | } 85 | 86 | function setPermissions() 87 | { 88 | return chmod($this->hta(), 644) && 89 | chmod($this->htp(), 644); 90 | } 91 | 92 | function createHtfiles() 93 | { 94 | if(!$this->hasHtaccess()) 95 | { 96 | $file = fopen($this->hta(), "w+"); 97 | if(!$file) 98 | return false; 99 | fclose($file); 100 | } 101 | 102 | if(!$this->hasHtpasswd()) 103 | { 104 | $file = fopen($this->htp(), "w+"); 105 | if(!$file) 106 | return false; 107 | fclose($file); 108 | } 109 | 110 | return true; 111 | } 112 | 113 | function icon() 114 | { 115 | return $this->isProtected() ? "🔒" : ""; 116 | } 117 | 118 | function getInfo() 119 | { 120 | $info = array("N/D", "N/D"); 121 | $lines = $this->getFileContent($this->htaFile); 122 | if(empty($lines)) 123 | return $info; 124 | 125 | foreach ($lines as $line) { 126 | if(preg_match("/AuthName/", $line)) 127 | $info[0] = $this->getInside($line); 128 | elseif(preg_match("/AuthUserFile/", $line)) 129 | $info[1] = $this->getInside($line); 130 | } 131 | 132 | return $info; 133 | } 134 | 135 | function isProtected() 136 | { 137 | if(!$this->hasHtaccess()) 138 | return false; 139 | 140 | $lines = $this->getFileContent($this->htaFile); 141 | if(empty($lines)) 142 | return false; 143 | $i = 0; 144 | while($i= count($lines)); 148 | } 149 | 150 | function addProtection() 151 | { 152 | if($this->isProtected()) 153 | return false; 154 | 155 | $fh = fopen($this->hta(), "a+"); 156 | if(!$fh) 157 | return false; 158 | $prot = "\n# HTAM - START \n# HTAccess Manager auto-generated script \nAuthType Basic \nAuthName \"Protected area\" \nAuthUserFile \"" . $this->htp() . "\"\nrequire valid-user \n# HTAM - END\n"; 159 | fwrite($fh, $prot); 160 | fclose($fh); 161 | return true; 162 | } 163 | 164 | function removeProtection() 165 | { 166 | $lines = $this->getFileContent($this->htaFile); 167 | if(empty($lines)) 168 | return false; 169 | 170 | $i = 0; 171 | while($i= count($lines)) 175 | return false; 176 | 177 | if($lines[$i-1] == "\n") 178 | unset($lines[$i-1]); 179 | 180 | for($j=$i; $j < $i+7; $j++) 181 | unset($lines[$j]); 182 | 183 | $cleaned = ""; 184 | foreach($lines as $line) 185 | $cleaned .= $line; 186 | 187 | $fh = fopen($this->hta(), "w+"); 188 | fwrite($fh, $cleaned); 189 | fclose($fh); 190 | 191 | return true; 192 | } 193 | 194 | function getUsers() 195 | { 196 | $users = array(); 197 | if(!$this->hasHtpasswd()) 198 | return $users; 199 | 200 | $lines = $this->getFileContent($this->htpFile); 201 | if(empty($lines)) 202 | return $users; 203 | 204 | foreach ($lines as $line) 205 | { 206 | $item = explode(":", $line); 207 | array_push($users, new HUser($item[0], $item[1], trim($item[2]))); 208 | } 209 | 210 | return $users; 211 | } 212 | 213 | function countAdmin() 214 | { 215 | $u = $this->getUsers(); 216 | $n = 0; 217 | if(!empty($u)) 218 | foreach ($u as $user) 219 | if($user->isAdmin()) 220 | $n++; 221 | 222 | return $n; 223 | } 224 | 225 | function findUser($name) 226 | { 227 | $u = $this->getUsers(); 228 | $i = 0; 229 | if(!empty($u)) 230 | while($iname() == $name) 233 | break; 234 | $i++; 235 | } 236 | 237 | if($i >= count($u)) 238 | return -1; 239 | 240 | return $i; 241 | } 242 | 243 | function changeUsers($users) 244 | { 245 | $checkOneAdmin = false; 246 | $cleaned = ""; 247 | $i = count($users); 248 | foreach($users as $user) 249 | { 250 | $cleaned .= $user->name().':'.$user->psw().':'.$user->isAdmin(); 251 | if($i-1 != 0) 252 | $cleaned .= "\n"; 253 | if(!$checkOneAdmin && $user->isAdmin()) 254 | $checkOneAdmin = true; 255 | $i--; 256 | } 257 | 258 | if(!$checkOneAdmin && $this->isProtected()) 259 | return false; 260 | 261 | 262 | $fh = fopen($this->htp(), "w+"); 263 | fwrite($fh, $cleaned); 264 | fclose($fh); 265 | return true; 266 | } 267 | 268 | function getSubDirFiles() 269 | { 270 | return array_diff(scandir($this->currentDir, 1), array('..', '.')); 271 | } 272 | } 273 | 274 | 275 | class HUser 276 | { 277 | private $username; 278 | private $password; 279 | private $admin; 280 | 281 | function __construct($n="none", $p="", $a=0) 282 | { 283 | $this->username = $n; 284 | $this->password = $p; 285 | $this->admin = $a; 286 | } 287 | 288 | public function name() 289 | { 290 | return $this->username; 291 | } 292 | 293 | public function psw() 294 | { 295 | return $this->password; 296 | } 297 | 298 | public function isAdmin() 299 | { 300 | return $this->admin; 301 | } 302 | 303 | public function changeUsername($name) 304 | { 305 | if(strlen($name) > 15 || strlen($name) < 3) 306 | return false; 307 | 308 | if(!preg_match("/^[a-zA-Z0-9\s_-]+$/", $name)) 309 | return false; 310 | 311 | $this->username = $name; 312 | return true; 313 | } 314 | 315 | public function changePassword($psw) 316 | { 317 | if(strlen($psw) > 32 || strlen($psw) < 4) 318 | return false; 319 | 320 | $pass = generatePassword($psw); 321 | 322 | $this->password = $pass; 323 | return true; 324 | } 325 | 326 | public function toggleAdmin($set) 327 | { 328 | $this->admin = $set ? 1 : 0; 329 | } 330 | } 331 | 332 | 333 | class HUpdates 334 | { 335 | private $version; 336 | private $payload; 337 | 338 | function __construct() 339 | { 340 | $this->version = VERSION; 341 | $this->payload = $this->checkNewVersion(); 342 | } 343 | 344 | private function checkNewVersion() 345 | { 346 | $json = file_get_contents('http://api.debug.ovh/htam.json'); 347 | if(!$json) 348 | return array(); 349 | 350 | return json_decode($json); 351 | } 352 | 353 | function currentVersion() 354 | { 355 | return $this->version; 356 | } 357 | 358 | function latestVersion() 359 | { 360 | if(!empty($this->payload)) 361 | return $this->payload->version; 362 | return "N/A"; 363 | } 364 | 365 | function info() 366 | { 367 | return $this->payload; 368 | } 369 | } 370 | 371 | 372 | function generatePassword($psw) 373 | { 374 | // Better than crypt() for portability 375 | return password_hash($psw, PASSWORD_BCRYPT); 376 | } 377 | 378 | function good($msg, $simple=0) 379 | { 380 | $cl = !$simple ? "good box" : "good"; 381 | return ''.$msg.''; 382 | } 383 | 384 | function bad($msg, $simple=0) 385 | { 386 | $cl = !$simple ? "bad box" : "bad"; 387 | return ''.$msg.''; 388 | } 389 | -------------------------------------------------------------------------------- /resources/dash.php: -------------------------------------------------------------------------------- 1 |
2 |

🏠 Dashboard

3 | 4 |

Welcome to the HTAccess Manager. From here, you can manage users and directory protection.

5 | 6 |
    7 |
  • Directory protection: isProtected() ? good("Active",1) : bad("Disabled",1) ;?> 8 | [change] 9 |
  • 10 |
  • Current Login Username: name() : "None";?>
  • 11 |
  • Total users: getUsers() ? 0 : count($htam->getUsers());?>
  • 12 |
13 |
-------------------------------------------------------------------------------- /resources/dir.php: -------------------------------------------------------------------------------- 1 |
2 |

📁 Directory Management

3 | 4 | hasHtaccess() && $htam->hasHtpasswd() && !$htam->checkPermissions()) 7 | { 8 | echo bad("The .htaccess or .htpasswd files are not readable or writable. Set the correct permissions (664) from FTP or attempt to change permissions. "); 9 | } 10 | 11 | if($a == 1) 12 | { 13 | if(!$htam->isProtected()) 14 | { 15 | if(!$htam->hasHtaccess() || !$htam->hasHtpasswd() || $htam->countAdmin() == 0) 16 | { 17 | echo bad("Before enabling protection, you must create htaccess and htpasswd and add at least one administrator in Manage users."); 18 | } 19 | else 20 | { 21 | if($htam->addProtection()) 22 | echo good("Directory protection activated."); 23 | else 24 | echo bad("Error: unable to add directory protection. Check file permissions."); 25 | } 26 | } 27 | else 28 | { 29 | if($htam->removeProtection()) 30 | echo good("Directory protection removed."); 31 | else 32 | echo bad("Error: unable to remove directory protection. Check file permissions."); 33 | } 34 | } 35 | elseif($a == 3) 36 | { 37 | if($htam->createHtfiles()) 38 | echo good("Files created successfully."); 39 | else 40 | echo bad("Error: unable to create one or more files to initialize the script. Change manually write permissions for this folder."); 41 | } 42 | elseif($a == 4) 43 | { 44 | if($htam->isProtected()) 45 | echo bad("You must disable protection to delete Htaccess."); 46 | elseif($htam->deleteHtaccess()) 47 | echo good("Htaccess deleted successfully."); 48 | else 49 | echo bad("Error: unable to delete Htaccess."); 50 | } 51 | elseif($a == 5) 52 | { 53 | if($htam->isProtected()) 54 | echo bad("You must disable protection to delete Htpasswd."); 55 | elseif($htam->deleteHtpasswd()) 56 | echo good("Htpasswd deleted successfully."); 57 | else 58 | echo bad("Error: unable to delete Htpasswd."); 59 | } 60 | elseif($a == 6) 61 | { 62 | if($htam->setPermissions()) 63 | echo good("File permissions (664) applied successfully. Now the script is able to work properly."); 64 | else 65 | echo bad("Error: unable to set permissions (664). You must do it manually from FTP."); 66 | } 67 | 68 | ?> 69 |
70 | 71 |
72 |

Informations

73 | 74 |
    75 |
  • Directory protection: isProtected() ? good("Active",1) : bad("Disabled",1) ;?> 76 | [change] 77 |
  • 78 |
  • htaccess: hasHtaccess() ? good("Yes",1) : bad("No",1) ;?>
  • 79 |
  • htpasswd: hasHtpasswd() ? good("Yes",1) : bad("No",1) ;?>
  • 80 |
  • Area name: getInfo()[0];?> 81 |
  • htaccess location: hta();?> 82 |
  • htpasswd location: htp();?> 83 |
84 |
85 | 86 |
87 |

Options

88 | 89 | 93 | 94 | 103 | 104 | Protected files and directories [reload | close]"; 109 | $subs = $htam->getSubDirFiles(); 110 | if(empty($subs)) 111 | echo "None"; 112 | else 113 | { 114 | echo "
    "; 115 | foreach ($subs as $sub => $name) 116 | { 117 | if(is_dir($name)) 118 | echo "
  • 🔸 $name/
  • "; 119 | else 120 | echo "
  • 🔹 $name
  • "; 121 | } 122 | echo "
"; 123 | } 124 | } 125 | 126 | ?> 127 |
-------------------------------------------------------------------------------- /resources/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-color: #444; 3 | color: #333; 4 | font-family: Verdana, sans-serif; 5 | font-size: 10.5pt; 6 | line-height: 150%; 7 | } 8 | h1,h2,h3,h4{ 9 | color: #333; 10 | } 11 | h1{ 12 | font-size: 140%; 13 | color: #4C5F7D; 14 | } 15 | header, nav, article, footer{ 16 | max-width: 1000px; 17 | width: auto; 18 | margin: 0 auto; 19 | padding: 10px; 20 | } 21 | header{ 22 | background-color: #CCC; 23 | border-bottom: 1px solid #AAA; 24 | text-align: center; 25 | border-top-right-radius: 3px; 26 | border-top-left-radius: 3px; 27 | } 28 | nav{ 29 | background-color: #e6e8ed; 30 | border-bottom: 1px solid #999; 31 | } 32 | nav span{ 33 | margin-right: 5px; 34 | display: inline-block; 35 | } 36 | a{ 37 | color: #3869b7; 38 | } 39 | a:hover{ 40 | color: #7d38b7; 41 | } 42 | footer a{ 43 | color: #444; 44 | } 45 | footer a:hover{ 46 | color: #CCC; 47 | } 48 | article{ 49 | background-color: #FAFAFA; 50 | min-height: 150px; 51 | } 52 | footer{ 53 | background-color: #999; 54 | color: #FFF; 55 | text-align: center; 56 | border-bottom-left-radius: 3px; 57 | border-bottom-right-radius: 3px; 58 | font-size: 80%; 59 | } 60 | span.good{ 61 | color: green; 62 | } 63 | span.bad{ 64 | color: darkred; 65 | } 66 | span.box{ 67 | display: block; 68 | border-radius: 3px; 69 | padding: 10px; 70 | background-color: #e6e8ed; 71 | } 72 | span.box.good{ 73 | background-color: #dce5da; 74 | } 75 | span.box.bad{ 76 | background-color: #e5dada; 77 | } 78 | ul.dir{ 79 | list-style-type: none; 80 | } 81 | 82 | ul.dir li{ 83 | margin-left: -15px; 84 | } 85 | input{ 86 | margin: 5px; 87 | } 88 | .responsive{ 89 | overflow-x: auto; 90 | } 91 | table{ 92 | width: 100%; 93 | } 94 | td{ 95 | padding: 3px; 96 | } 97 | tr{ 98 | background-color: #E9E9E9; 99 | } 100 | tr:nth-child(odd){ 101 | background-color: #FFF; 102 | } 103 | #checker{ 104 | font-size: 80%; 105 | } 106 | .tdcenter td{ 107 | text-align: center; 108 | } -------------------------------------------------------------------------------- /resources/updates.php: -------------------------------------------------------------------------------- 1 |
2 |

☕ Updates

3 | latestVersion() == "N/A") 7 | echo bad("Unable to check for new updates. Try later or checkout the official repository."); 8 | elseif($hup->currentVersion() != $hup->latestVersion()) 9 | echo bad("Your version is not up to date."); 10 | else 11 | echo good("Your version is up to date."); 12 | ?> 13 | 14 |

Updates checker

15 |
    16 |
  • Current version: currentVersion();?>
  • 17 |
  • Latest version: latestVersion();?>
  • 18 |
  • Github repository for updates:
  • 19 |
20 | 21 | info())) 23 | { 24 | echo "
"; 25 | foreach ($hup->info() as $key => $value) 26 | { 27 | echo " 28 | 29 | 30 | "; 31 | } 32 | echo "
$key$value
"; 33 | } 34 | ?> 35 | 36 |
37 | -------------------------------------------------------------------------------- /resources/users.php: -------------------------------------------------------------------------------- 1 |
2 |

👥 User management

3 | 4 | getUsers(); 7 | $edit = isset($_GET['edit']) ? $_GET['edit'] : ""; 8 | 9 | if($a == 1) 10 | { 11 | $un = $_POST['uname']; 12 | $up = $_POST['upass']; 13 | $urp = $_POST['urpass']; 14 | 15 | $find = $htam->findUser($un); 16 | $user = $find > -1 ? $users[$find] : new HUser(); 17 | 18 | 19 | if(!$user->changeUsername($un)) 20 | { 21 | echo bad("The username must contain only alphanumeric characters, dash, underscore and spaces (from 3 to 15 characters long)."); 22 | } 23 | elseif(!$user->changePassword($up)) 24 | { 25 | echo bad("The password must be at least 4 characters and maximum 32 characters long."); 26 | } 27 | elseif($up != $urp) 28 | { 29 | echo bad("The password repeated is different."); 30 | } 31 | else 32 | { 33 | if($find > -1) 34 | $users[$find] = $user; 35 | else 36 | array_push($users, $user); 37 | 38 | 39 | if($htam->changeUsers($users)) 40 | echo good("User $un has been added/edited successfully.
41 | Username: $un - Password: $up"); 42 | else 43 | echo bad("Error: unable to update users file. Check permissions."); 44 | } 45 | } 46 | elseif($a == 2 && !empty($edit)) 47 | { 48 | $find = $htam->findUser($edit); 49 | $user = $find > -1 ? $users[$find] : ""; 50 | if(empty($user)) 51 | echo bad("The user selected has not been found."); 52 | elseif(isset($me) && $user->name() == $me->name() && $htam->isProtected()) 53 | echo bad("You can't delete yourself while directory protection is active."); 54 | else 55 | { 56 | unset($users[$find]); 57 | if($htam->changeUsers($users)) 58 | echo good("The user has been removed permanently."); 59 | else 60 | echo bad("Error: unable to update users file. Check permissions."); 61 | 62 | } 63 | } 64 | elseif($a == 3 && !empty($edit)) 65 | { 66 | $find = $htam->findUser($edit); 67 | $user = $find > -1 ? $users[$find] : ""; 68 | if(empty($user)) 69 | echo bad("The user selected has not been found."); 70 | elseif( ($htam->countAdmin() == 1 || (isset($me) && $user->name() == $me->name()) ) 71 | && $user->isAdmin() && $htam->isProtected()) 72 | echo bad("You can't remove the last administrator or yourself as administrator while protection is enabled."); 73 | else 74 | { 75 | $users[$find]->toggleAdmin($user->isAdmin() ? 0 : 1); 76 | if($htam->changeUsers($users)) 77 | echo good("The role of the user {$user->name()} has been changed."); 78 | else 79 | echo bad("Error: unable to update users file. Check permissions."); 80 | 81 | } 82 | } 83 | 84 | ?> 85 |
86 | 87 | 107 | 108 |
109 |

Add / edit user

110 |

If the username is already in use, the password will be overrided with the new one.

111 |
112 | 113 |
114 | 115 |
116 | 117 |
118 |
119 | 120 |
121 | 122 |

Users list

123 | 124 | Total users: ".count($users).", Administrators: ".$htam->countAdmin()." "; 130 | echo "
"; 131 | foreach ($users as $user) 132 | { 133 | echo ""; 134 | echo ""; 135 | echo ""; 136 | echo ""; 137 | if(!$user->isAdmin()) 138 | echo ""; 139 | else 140 | echo ""; 141 | echo ""; 142 | echo ""; 143 | } 144 | echo "
{$user->name()}".($user->isAdmin() ? bad("🤠 administrator",1) : good("😃 user",1))."edit passwordset adminset userdelete
"; 145 | } 146 | 147 | ?> 148 |
--------------------------------------------------------------------------------