PageRenderTime 64ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 2ms

/authman/index.php

https://bitbucket.org/dahlo/roster
PHP | 8054 lines | 5919 code | 1256 blank | 879 comment | 1416 complexity | c525aa1c23a95d0f9d0fae8dfef1e79d MD5 | raw file
Possible License(s): LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * AuthMan Free
  4. *
  5. * @copyright Copyright (c) 2008 Authman Inc. (http://www.authman.com)
  6. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL
  7. * @link http://www.authman.com
  8. * @version 1.0.0
  9. */
  10. ini_set('zlib.output_compression','Off');
  11. define('AUTHMAN_DIR', dirname(__FILE__));
  12. /**
  13. * AuthMan Class (Free Version)
  14. *
  15. * @copyright Copyright (c) 2008 Authman Inc. (http://www.authman.com)
  16. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL
  17. * @link http://www.authman.com
  18. */
  19. class Authman
  20. {
  21. /**
  22. * Class version, const
  23. *
  24. * @access private
  25. */
  26. var $AUTHMAN_VERSION = '1.1.0';
  27. /**
  28. * Apache ServerRoot
  29. *
  30. * @access private
  31. * @var string
  32. */
  33. var $_serverRoot = '/etc/httpd';
  34. /**
  35. * Authman directory
  36. *
  37. * private @var string
  38. */
  39. var $_basePath;
  40. /**
  41. * Default Ini file
  42. *
  43. * @access private
  44. * @var string
  45. */
  46. var $_iniFile = 'config/config.ini';
  47. /**
  48. * Config settings
  49. *
  50. * @access private
  51. * @var array
  52. */
  53. var $_configArray = array('language' => 'english',
  54. 'login' => 'admin',
  55. 'password' => 'admin',
  56. 'demo' => 0,
  57. 'manual_edit' => 1,
  58. 'access_file' => '.htaccess',
  59. 'authuser_file' => '.htpasswd',
  60. 'authname' => 'Protected by Authman',
  61. 'allowsignup' => 0,
  62. 'autoapprove' => 0,
  63. 'encryption' =>'md5');
  64. /**
  65. * Language array
  66. *
  67. * @access private
  68. * @var array
  69. */
  70. var $_langArray = array('messages'=>array(),
  71. 'warnings'=>array(),
  72. 'errors'=>array());
  73. /**
  74. * File Paths
  75. *
  76. * @access private
  77. * @var array
  78. */
  79. var $_filePathsArray = array('configfile'=>null,
  80. 'langfile'=>null,
  81. 'accessfile'=>null,
  82. 'authadminfile'=>null,
  83. 'authuserfile' =>null,
  84. 'authgroupfile'=>null,
  85. 'accessfile_dist'=>null,
  86. 'authuserfile_dist' =>null,
  87. 'authgroupfile_dist'=>null,
  88. 'signupfile'=>null);
  89. /**
  90. * Raw File Contents (by url hash)
  91. *
  92. * @access private
  93. * @var array
  94. */
  95. var $_fileContentsArray = array();
  96. /**
  97. * Parsed File Data (by url hash)
  98. *
  99. * @access private
  100. * @var array
  101. */
  102. var $_fileDataArray = array();
  103. /**
  104. * Access Rules Information (by url hash)
  105. *
  106. * @access private
  107. * @var array
  108. */
  109. var $_accessRulesArray = array();
  110. /**
  111. * Runtime variables
  112. *
  113. * @access private
  114. * @var array
  115. */
  116. var $_runtimeArray = null;
  117. /**
  118. * Error message
  119. *
  120. * @access private
  121. * @var string
  122. */
  123. var $_error = null;
  124. /**
  125. * @access private
  126. * @var array
  127. */
  128. var $_tplsArray = array();
  129. /**
  130. * Authman Constructor
  131. *
  132. * @access public
  133. * @params array|null $config
  134. * @return void
  135. */
  136. function Authman( $config=array() )
  137. {
  138. // base prefix
  139. $this->_basePath = dirname(__FILE__);
  140. // overwrite ini file name
  141. if (isset($config['ini'])) {
  142. $this->_iniFile = $config['ini'];
  143. }
  144. // loading ini file
  145. $iniFilePath = $this->makePath( $this->_basePath, $this->_iniFile );
  146. $this->_filePathsArray[ 'configfile' ] = $iniFilePath;
  147. if (is_file($iniFilePath) && is_readable($iniFilePath) ) {
  148. $cfg = @parse_ini_file( $iniFilePath, false );
  149. if (isset($cfg)) {
  150. $this->_configArray = array_merge($this->_configArray, $cfg);
  151. }
  152. }
  153. // overwrite language
  154. if (isset($config['language'])) {
  155. $this->_configArray['language'] = $config['language'];
  156. }
  157. // loading language file
  158. $langFilePath = $this->makePath($this->_basePath . DIRECTORY_SEPARATOR . 'languages',
  159. $this->_configArray['language'] . '.lng' );
  160. $this->_filePathsArray[ 'langfile' ] = $langFilePath;
  161. if (!is_file($langFilePath) || !is_readable($langFilePath) ) {
  162. // we will trying load default language file
  163. $langFilePath = $this->makePath($this->_basePath . DIRECTORY_SEPARATOR . 'languages',
  164. 'english.lng' );
  165. }
  166. if (is_file($langFilePath) && is_readable($langFilePath) ) {
  167. $this->_langArray = array_merge($this->_langArray, @parse_ini_file($langFilePath, true));
  168. }
  169. // set access file path
  170. $path = $this->makePath( $this->_basePath . DIRECTORY_SEPARATOR . '..',
  171. $this->_configArray['access_file'] );
  172. $this->_filePathsArray[ 'accessfile' ] = $path;
  173. #if (is_file($path) && is_readable($path)) {
  174. $this->readFileByType( 'accessfile' );
  175. #}
  176. // set admin htpasswd file path
  177. $basedir = $this->_basePath . DIRECTORY_SEPARATOR . 'var';
  178. $path = $this->makePath( $basedir, '.htadmin' );
  179. $this->_filePathsArray[ 'authadminfile' ] = $path;
  180. // set default file paths
  181. $path = $this->makePath( $basedir, 'htaccess_dist' );
  182. $this->_filePathsArray[ 'accessfile_dist' ] = $path;
  183. $path = $this->makePath( $basedir, 'htpasswd_dist' );
  184. $this->_filePathsArray[ 'authuserfile_dist' ] = $path;
  185. $path = $this->makePath( $basedir, 'htgroup_dist' );
  186. $this->_filePathsArray[ 'authgroupfile_dist' ] = $path;
  187. $path = $this->makePath( $basedir, 'signups' );
  188. $this->_filePathsArray[ 'signupfile' ] = $path;
  189. // loading runtime stats
  190. }
  191. /**
  192. * Return class version
  193. *
  194. * @access public
  195. * @return string
  196. */
  197. function getVersion()
  198. {
  199. return $this->AUTHMAN_VERSION;
  200. }
  201. /**
  202. * Return true if demo mode is on
  203. *
  204. * @access public
  205. * @return string
  206. */
  207. function isDemo()
  208. {
  209. return $this->_configArray['demo'] == 1;
  210. }
  211. /**
  212. * Return true if menual edit is allowed
  213. *
  214. * @access public
  215. * @return string
  216. */
  217. function isManualEdit()
  218. {
  219. return $this->_configArray['manual_edit'] == 1;
  220. }
  221. /**
  222. * Return configuration value by name
  223. *
  224. * @access public
  225. * @param string $name
  226. * @return string
  227. */
  228. function getConfigValue( $name )
  229. {
  230. if (!isset($name) || !isset($this->_configArray[$name])) {
  231. return false;
  232. }
  233. return $this->_configArray[$name];
  234. }
  235. /***************************************************************************
  236. * Member zone related functions
  237. **************************************************************************/
  238. /**
  239. * Logging as user
  240. *
  241. * @access public
  242. * @param string $username
  243. * @param string encpass
  244. * @return bool
  245. */
  246. function loginAs( $username, $encpass )
  247. {
  248. $_SESSION['am_u'] = base64_encode( $username );
  249. $_SESSION['am_c'] = md5( $encpass );
  250. $user = $this->fetchRecordByType( 'authuserfile', $username );
  251. if (false == $user) {
  252. $user = $this->fetchRecordByType( 'authadminfile', $username, true );
  253. if (false == $user) {
  254. return false;
  255. }
  256. $err = $this->getError();
  257. $this->setRuntimeValue('lastloggedin_ts', time());
  258. $this->setRuntimeValue('lastloggedin_ip', $_SERVER['REMOTE_ADDR'], true);
  259. $this->setError($err);
  260. }
  261. return true;
  262. }
  263. /**
  264. * Return authenticated user data
  265. *
  266. * @access public
  267. * @return array|false
  268. */
  269. function getAuthenticatedUser()
  270. {
  271. // checking session cookie
  272. $isadmin = false;
  273. $user = null;
  274. $username = $codedpass = $rawpass = null;
  275. if (isset($_SESSION) && isset($_SESSION['am_u'])
  276. && isset($_SESSION['am_c'])) {
  277. $username = base64_decode($_SESSION['am_u']);
  278. $codedpass = $_SESSION['am_c']; // md5
  279. } else if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
  280. $username = $_SERVER['PHP_AUTH_USER'];
  281. $rawpass = $_SERVER['PHP_AUTH_PW'];
  282. }
  283. if (!isset($username) || $username=='') {
  284. return false;
  285. }
  286. // checking admins first
  287. $user = $this->fetchRecordByType('authadminfile', $username, true);
  288. if ($user) {
  289. $isadmin = true;
  290. } else {
  291. $user = $this->fetchRecordByType('authuserfile', $username);
  292. }
  293. if (false == $user || !isset($user['pass'])) {
  294. return false;
  295. }
  296. if (isset($rawpass)) {
  297. $encpass = $this->htcrypt($rawpass, $user['pass']);
  298. if ($encpass != $user['pass']) {
  299. return false;
  300. }
  301. } else if (md5($user['pass']) != $codedpass) {
  302. return false;
  303. }
  304. $user['isadmin'] = $isadmin;
  305. return $user;
  306. }
  307. /**
  308. * Return true if user is authenticated
  309. *
  310. * @access public
  311. * @return bool
  312. */
  313. function isAuthenticated()
  314. {
  315. return false == $this->getAuthenticatedUser() ? false : true;
  316. }
  317. /**
  318. * Return true if user is authenticated by basic auth method
  319. *
  320. * @access public
  321. * @return bool
  322. */
  323. function isAuthenticatedByBasicAuth()
  324. {
  325. $user = $this->getAuthenticatedUser();
  326. if (false == $user) {
  327. return false;
  328. }
  329. if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) {
  330. return false;
  331. }
  332. $encpass = $this->htcrypt($_SERVER['PHP_AUTH_PW'], $user['pass']);
  333. if ($encpass != $user['pass']) {
  334. return false;
  335. }
  336. return true;
  337. }
  338. /**
  339. * Return true if current authenticated user has administrator priviledges
  340. *
  341. * @access public
  342. * @return bool
  343. */
  344. function isAdmin()
  345. {
  346. $user = $this->getAuthenticatedUser();
  347. if (false == $user) {
  348. return false;
  349. }
  350. return isset($user['isadmin']) && $user['isadmin'] ? true : false;
  351. }
  352. /***************************************************************************
  353. * Crypt Utilties
  354. **************************************************************************/
  355. /**
  356. * Encrypt text with crypt function
  357. *
  358. * @access public
  359. * @param string $text
  360. * @param string|null $salt
  361. * @param string|null $prefix
  362. * @return string
  363. */
  364. function encrypt_saltcrypt( $text, $salt='', $prefix='' )
  365. {
  366. if ($salt == 'DES') {
  367. $salt = CRYPT_STD_DES == 1 ? 'r1' : '';
  368. }
  369. if ($salt == 'EXT_DES') {
  370. $salt = CRYPT_EXT_DES == 1 ? '_J9..pre' : '';
  371. }
  372. if ($salt == 'MD5') {
  373. $salt = CRYPT_MD5 == 1 ? '$1$pre$' : '';
  374. }
  375. if ($salt == '') {
  376. mt_srand((double)microtime()*1000000);
  377. for ($i=0; $i<CRYPT_SALT_LENGTH; $i++)
  378. $salt .= substr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./",
  379. mt_rand() & 63, 1);
  380. }
  381. return $prefix . crypt($text, $salt);
  382. }
  383. /**
  384. * Encrypt text with crypt function
  385. *
  386. * @access public
  387. * @param string $text
  388. * @param string|null $salt
  389. * @return string
  390. */
  391. function htcrypt( $text, $salt=null )
  392. {
  393. $method = $this->_configArray['encryption'];
  394. if (isset($salt) && substr($salt, 0, 6) == '$apr1$') {
  395. $method = 'md5';
  396. $salt = substr($salt, 6);
  397. }
  398. // apr1-md5
  399. if ($method == 'md5') {
  400. if (CRYPT_MD5 == 1) {
  401. return $this->crypt_apr1_md5($text, $salt);
  402. }
  403. }
  404. // DES
  405. if (!isset($salt)) {
  406. mt_srand((double)microtime()*1000000);
  407. for ($i=0; $i<CRYPT_SALT_LENGTH; $i++) {
  408. $salt .= substr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./", mt_rand() & 63, 1);
  409. }
  410. }
  411. return crypt($text, $salt);
  412. }
  413. /**
  414. * Encryption function
  415. *
  416. * @access public
  417. * @param string $plainpasswd
  418. * @param string $salt
  419. * @return string
  420. */
  421. function crypt_apr1_md5($plainpasswd, $salt) {
  422. if (!isset($salt)) {
  423. $salt = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz0123456789"), 0, 8);
  424. } else {
  425. $salt = substr($salt, 0, 8);
  426. }
  427. $len = strlen($plainpasswd);
  428. $text = $plainpasswd.'$apr1$'.$salt;
  429. $bin = pack("H32", md5($plainpasswd.$salt.$plainpasswd));
  430. for($i = $len; $i > 0; $i -= 16) { $text .= substr($bin, 0, min(16, $i)); }
  431. for($i = $len; $i > 0; $i >>= 1) { $text .= ($i & 1) ? chr(0) : $plainpasswd{0}; }
  432. $bin = pack("H32", md5($text));
  433. for($i = 0; $i < 1000; $i++) {
  434. $new = ($i & 1) ? $plainpasswd : $bin;
  435. if ($i % 3) $new .= $salt;
  436. if ($i % 7) $new .= $plainpasswd;
  437. $new .= ($i & 1) ? $bin : $plainpasswd;
  438. $bin = pack("H32", md5($new));
  439. }
  440. $tmp = '';
  441. for ($i = 0; $i < 5; $i++) {
  442. $k = $i + 6;
  443. $j = $i + 12;
  444. if ($j == 16) $j = 5;
  445. $tmp = $bin[$i].$bin[$k].$bin[$j].$tmp;
  446. }
  447. $tmp = chr(0).chr(0).$bin[11].$tmp;
  448. $tmp = strtr(strrev(substr(base64_encode($tmp), 2)),
  449. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
  450. "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
  451. return "$"."apr1"."$".$salt."$".$tmp;
  452. }
  453. /***************************************************************************
  454. * File System Utilties
  455. **************************************************************************/
  456. /**
  457. * Construct path from base path and file name
  458. *
  459. * @access public
  460. * @param string $basePath
  461. * @param string $fileName
  462. * @param string|null $dirsep
  463. * @return string
  464. */
  465. function makePath($basePath, $fileName, $dirsep=DIRECTORY_SEPARATOR)
  466. {
  467. // Windows
  468. if (preg_match('/^[A-Z]:\\\/i', $fileName)) {
  469. return $this->getNormalizedPath( $fileName );
  470. }
  471. // Unix and other
  472. if (substr($fileName,0,1)=='/' || substr($fileName,0,1)==$dirsep) {
  473. return $this->getNormalizedPath( $fileName );
  474. }
  475. return $this->getNormalizedPath( $basePath . $dirsep . $fileName );
  476. }
  477. /**
  478. * Normalize given path
  479. *
  480. * @access public
  481. * @param mixed $path
  482. * @param string|null $dirsep
  483. * @return mixed
  484. */
  485. function getNormalizedPath( $path, $dirsep=DIRECTORY_SEPARATOR )
  486. {
  487. if (is_array($path)) {
  488. $pathArray = array();
  489. foreach($path as $p) {
  490. $pathArray[] = $this->getNormalizedPath($p, $dirsep);
  491. }
  492. return $pathArray;
  493. }
  494. $prefix = '';
  495. // if not Windows
  496. if (!preg_match('/^[A-Z]:\\\/i', $path)) {
  497. $prefix = $dirsep;
  498. }
  499. $path = str_replace('/', $dirsep, $path);
  500. $path = str_replace('\\', $dirsep, $path);
  501. $parts = explode($dirsep, $path);
  502. $todown=0;
  503. for ($i = count($parts)-1; $i >= 0; $i--) {
  504. if (empty($parts[$i]) || $parts[$i] == '.') {
  505. array_splice( $parts, $i, 1);
  506. continue;
  507. }
  508. if ($parts[$i] == '..') {
  509. array_splice( $parts, $i, 1);
  510. if ($i > 0) {
  511. $todown++;
  512. }
  513. continue;
  514. }
  515. if ($todown) {
  516. # warning: not works for complex paths like /root/path/../path/../../the/end
  517. array_splice( $parts, $i-($todown-1), $todown);
  518. $todown = 0;
  519. }
  520. }
  521. return $prefix . implode( $dirsep, $parts );
  522. }
  523. /**
  524. * Return full path to a file specified by type
  525. *
  526. * @access public
  527. * @param string $filetype
  528. * @param string|null $dir
  529. * @return string
  530. */
  531. function getPathByType( $filetype, $dir=DIRECTORY_SEPARATOR )
  532. {
  533. $ln = strtolower($filetype);
  534. if ($ln == 'protecteddirectory') {
  535. return $this->getNormalizedPath($this->_basePath . $dir . '..');
  536. }
  537. if ($ln == 'phpmailer') {
  538. return implode($dir, array($this->_basePath, 'contrib',
  539. 'phpmailer', 'class.phpmailer.php'));
  540. }
  541. if ($ln == 'tinymcejs') {
  542. return implode($dir, array($this->_basePath,
  543. 'contrib', 'tinymce', 'jscripts',
  544. 'tiny_mce', 'tiny_mce.js'));
  545. }
  546. if ($ln == 'magpierss') {
  547. return implode($dir, array($this->_basePath, 'contrib',
  548. 'magpierss', 'rss_fetch.inc'));
  549. }
  550. if (!isset($this->_filePathsArray[$filetype])) {
  551. return false;
  552. }
  553. return $this->_filePathsArray[$filetype];
  554. }
  555. /**
  556. * Return default file path by type
  557. *
  558. * @access public
  559. * @param string $filetype
  560. * @return string
  561. */
  562. function getDefaultFilePathByType( $filetype )
  563. {
  564. if ($filetype == 'authuserfile') {
  565. return dirname($this->getPathByType('accessfile'))
  566. . DIRECTORY_SEPARATOR
  567. . $this->getConfigValue('authuser_file');
  568. }
  569. return false;
  570. }
  571. /**
  572. * Returns url by type
  573. *
  574. * @access public
  575. * @param string $filetype
  576. * @param string|null $fulurl
  577. * @return strung
  578. */
  579. function getUrlByType( $filetype, $fullurl=false )
  580. {
  581. // base uri
  582. $server = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];
  583. $port = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80;
  584. $uri_self = $_SERVER['PHP_SELF'];
  585. $uri = dirname($uri_self);
  586. if ($filetype == 'base') {
  587. $uri .= '/';
  588. }
  589. if ($filetype == 'protected') {
  590. $uri = $this->getNormalizedPath($uri . '/../', '/');
  591. }
  592. if ($filetype == 'errordocument401') {
  593. $uri = $uri_self .'?page=401';
  594. }
  595. if ($filetype == 'login') {
  596. $uri = $uri_self .'?page=login';
  597. }
  598. if ($filetype == 'tinymcejs') {
  599. $uri .= '/contrib/tinymce/jscripts/tiny_mce/tiny_mce.js';
  600. }
  601. if (!$fullurl) {
  602. return $uri;
  603. }
  604. return 'http://'.$server . ($port != 80 ? ':'.$port : '') . $uri;
  605. }
  606. /**
  607. * Set file path
  608. *
  609. * @access public
  610. * @param string $filetype
  611. * @param string $filepath
  612. * @return void
  613. */
  614. function setFilePathByType( $filetype, $filepath )
  615. {
  616. if (!isset($filepath)) {
  617. return false;
  618. }
  619. $hash = md5( $filepath );
  620. $this->_fileContentsArray[ $hash ] = null;
  621. $this->_fileDataArray[ $hash ] = null;
  622. $this->_filePathsArray[ $filetype ] = $filepath;
  623. }
  624. /**
  625. * Return temporary file name
  626. *
  627. * @access public
  628. * @return string
  629. */
  630. function getTempFilePath()
  631. {
  632. return $this->_basePath . DIRECTORY_SEPARATOR . 't_' . time() . rand(0, 1000);
  633. }
  634. /***************************************************************************
  635. * String functions
  636. **************************************************************************/
  637. /***************************************************************************
  638. * Disk Level File Operations
  639. **************************************************************************/
  640. /**
  641. * Write default deny file to disk
  642. *
  643. * @access private
  644. * @param string $filePath
  645. * @return bool
  646. */
  647. function writeDenyFile( $filePath )
  648. {
  649. $fh = @fopen($filePath, 'w');
  650. if (false == $fh) {
  651. return false;
  652. }
  653. @fwrite($fh, "# Automatically Created by Autman Free\n");
  654. @fwrite($fh, "order deny,allow\n");
  655. @fwrite($fh, "deny from all\n");
  656. @fclose($fh);
  657. return true;
  658. }
  659. /**
  660. * Read and parse file
  661. *
  662. * @access private
  663. * @param string $filetype
  664. * @return bool
  665. */
  666. function readFileByType( $filetype )
  667. {
  668. $path = $this->getPathByType( $filetype );
  669. if (false == $path) {
  670. return false;
  671. }
  672. $hash = md5($path);
  673. $this->_fileContentsArray[$hash] = array();
  674. $this->_fileDataArray[$hash] = array();
  675. if (!is_file($path)) {
  676. $this->setError( $this->E('NOSUCHFILE', $path) );
  677. return false;
  678. }
  679. if (is_file($path) && !is_readable($path)) {
  680. $this->setError( $this->E('FILENOTREADBLE', $path) );
  681. return false;
  682. }
  683. $fh = @fopen($path, 'r');
  684. if (false == $fh) {
  685. $this->setError( $this->E('FILEOPENFAILED', $path) );
  686. return false;
  687. }
  688. $contents = $buf = null;
  689. $maxbytes = 2048000;
  690. $bytes = 0;
  691. while (!feof($fh) && $bytes < $maxbytes && ($buf = fread($fh, $maxbytes-$bytes))) {
  692. $contents .= $buf;
  693. }
  694. fclose($fh);
  695. return $this->setFileContentsByType( $filetype, $contents );
  696. }
  697. /**
  698. * Save file
  699. *
  700. * @access public
  701. * @param string $filetype
  702. * @param bool|null $saveRawData
  703. * @param string|null $contents
  704. * @return bool
  705. */
  706. function saveFileByType( $filetype, $saveRawData=false, $contents=null, $parseTemplates=false )
  707. {
  708. $path = $this->getPathByType( $filetype );
  709. if (!$path) {
  710. return false;
  711. }
  712. if (!isset($contents)) {
  713. $contents = $this->getFileContentsByType( $filetype, $saveRawData, $parseTemplates );
  714. }
  715. // Saving in DEMO mode is disabled
  716. if ($this->isDemo()) {
  717. $this->setError( $this->W('DEMOISON') );
  718. return false;
  719. }
  720. if (!is_file($path) && !is_writable(dirname($path))) {
  721. $this->setError( $this->E('DIRNOTWRITABLE', dirname($path)) );
  722. return false;
  723. }
  724. if (is_file($path) && !is_writable($path)) {
  725. $this->setError( $this->E('FILENOTWRITABLE', $path) );
  726. return false;
  727. }
  728. $fh = @fopen($path, 'w');
  729. if (!$fh) {
  730. $this->setError( $this->E('FILEOPENFAILED', $path) );
  731. return false;
  732. }
  733. if ($contents != '') {
  734. if (!fwrite($fh, $contents)) {
  735. $this->setError( $this->E('WRITEFAILED', $path) );
  736. return false;
  737. }
  738. }
  739. @fclose($fh);
  740. if (!$this->readFileByType( $filetype )) {
  741. return false;
  742. }
  743. return true;
  744. }
  745. /**
  746. * Reset protected directory
  747. *
  748. * @access public
  749. * @retrun bool
  750. */
  751. function resetProtectedDirectory()
  752. {
  753. $src = $this->getPathByType( 'accessfile_dist');
  754. $dst = $this->getPathByType( 'accessfile' );
  755. if (false == $this->copyFile( $src, $dst )) {
  756. return false;
  757. }
  758. $this->readFileByType( 'accessfile' );
  759. $result = true;
  760. $filesArray = array('authuserfile'); // , 'authgroupfile');
  761. foreach ($filesArray as $file) {
  762. $src = $this->getPathByType( $file . '_dist');
  763. $dst = $this->getPathByType( $file );
  764. if (isset($src) && isset($dst) && is_file($src)) {
  765. if (false == $this->copyFile( $src, $dst )) {
  766. $result = false;
  767. }
  768. }
  769. }
  770. return $result;
  771. }
  772. /**
  773. * Copy file
  774. *
  775. * @access public
  776. * @param string $src
  777. * @param string $dst
  778. * @return bool
  779. */
  780. function copyFile( $src, $dst )
  781. {
  782. if ($src == false) {
  783. $this->setError( $this->E('INVALIDREQUEST') . ' [source]');
  784. return false;
  785. }
  786. if ($dst == false) {
  787. $this->setError( $this->E('INVALIDREQUEST') . ' [destination]');
  788. return false;
  789. }
  790. // Saving in DEMO mode is disabled
  791. if ($this->isDemo()) {
  792. $this->setError( $this->W('DEMOISON') );
  793. return false;
  794. }
  795. if (!is_file($dst) && !is_writable(dirname($dst))) {
  796. $this->setError( $this->E('DIRNOTWRITABLE', dirname($dst)) );
  797. return false;
  798. }
  799. if (is_file($dst) && !is_writable($dst)) {
  800. $this->setError( $this->E('FILENOTWRITABLE', $dst) );
  801. return false;
  802. }
  803. if (!is_file($src) || !is_readable($src)) {
  804. $this->setError( $this->E('FILENOTREADBLE', $src) );
  805. return false;
  806. }
  807. if (false == copy( $src, $dst )) {
  808. $this->setError( $this->E('FILECOPYFAILED', $src) );
  809. return false;
  810. }
  811. return true;
  812. }
  813. /***************************************************************************
  814. * Contents
  815. **************************************************************************/
  816. /**
  817. * Return file contents
  818. *
  819. * @access public
  820. * @param string $filetype
  821. * @param bool|null $getRawData
  822. * @return string
  823. */
  824. function getFileContentsByType( $filetype, $getRawData=false, $parseTemplates=false )
  825. {
  826. $path = $this->getPathByType( $filetype );
  827. if (false == $path) {
  828. return false;
  829. }
  830. $hash = md5( $path );
  831. if (false == $getRawData) {
  832. $data = $this->getFileDataByType( $filetype );
  833. $text = '';
  834. // build contents from parsed data
  835. if ($filetype == 'accessfile') {
  836. if ($parseTemplates) {
  837. foreach ($data as $k=>$v) {
  838. $data[$k] = preg_replace('/%PROTECTEDDIRECTORY%/', $am->getPathByType('protecteddirectory'), $v);
  839. }
  840. }
  841. $text = implode("\n", $data);
  842. } else if (($filetype=='authuserfile' || $filetype=='authadminfile' ||
  843. $filetype=='signupfile') && is_array($data)) {
  844. foreach ($data as $user) {
  845. if (isset($user['pass_raw'])) {
  846. // $pass = $this->encrypt_saltcrypt( $user['pass_raw'], 'DES' );
  847. $pass = $this->htcrypt( $user['pass_raw'] ); // salt automatically generated
  848. } else {
  849. $pass = $user['pass'];
  850. }
  851. $text .= $user['name'] . ':' . $pass;
  852. if (isset($user['info']) || isset($user['email'])) {
  853. $text .= ':';
  854. $text .= isset($user['info']) ? $user['info'] . ':' : '';
  855. if (isset($user['email'])) {
  856. $text .= $user['email'];
  857. }
  858. }
  859. if ($filetype=='signupfile') {
  860. $text .= ':' . (isset($user['ts']) ? $user['ts'] : '');
  861. $text .= ':' . (isset($user['remoteaddr']) ? $user['remoteaddr'] : '');
  862. $text .= ':' . (isset($user['referer']) ? $user['referer'] : '');
  863. }
  864. $text .= "\n";
  865. }
  866. }
  867. return $text;
  868. }
  869. /* fetching raw data */
  870. if (!isset($this->_fileContentsArray[ $hash ])) {
  871. if (false == $this->readFileByType( $filetype )) {
  872. return false;
  873. }
  874. }
  875. if (!isset($this->_fileContentsArray[ $hash ])) {
  876. return '';
  877. }
  878. if (!is_array($this->_fileContentsArray[$hash])) {
  879. return $this->_fileContentsArray[$hash];
  880. }
  881. return implode("\n", $this->_fileContentsArray[$hash]);
  882. }
  883. /**
  884. * Parse files
  885. *
  886. * @access public
  887. * @param string $filetype
  888. * @param string $contents
  889. * @return bool
  890. */
  891. function parseFileContentsByType( $filetype, $contents )
  892. {
  893. $path = $this->getPathByType( $filetype );
  894. if (false == $path) {
  895. $this->setError( $this->W('NOTDEFINED', $filetype) );
  896. return false;
  897. }
  898. $hash = md5( $path );
  899. $this->_fileDataArray[$hash] = array();
  900. $this->_accessRulesArray[$hash] = array('order'=>null);
  901. $lArray = split("[\n\r]+", $contents);
  902. // no data
  903. if (count($lArray) < 0) {
  904. return true;
  905. }
  906. if ($filetype == 'accessfile') {
  907. $rows = array();
  908. $hash = md5( $this->getPathByType( $filetype ) );
  909. foreach($lArray as $l) {
  910. if (preg_match('/^\s*Auth(User|Group)File\s+(.+)/i', $l, $matches)) {
  911. $authfiletype = 'auth' . strtolower($matches[1]) . 'file';
  912. $path = $this->makePath( $this->_serverRoot, $matches[2] );
  913. $this->_filePathsArray[ $authfiletype ] = $path;
  914. }
  915. if (preg_match('/^\s*AuthType\s+(.+)/i', $l, $matches)) {
  916. $val = strtolower(trim($matches[1]));
  917. $val = stripslashes($val);
  918. $this->_accessRulesArray[$hash]['authtype'] = $val;
  919. }
  920. if (preg_match('/^\s*AuthName\s+"?(.+?)"?\s*$/i', $l, $matches)) {
  921. $val = trim($matches[1]);
  922. $val = stripslashes( $val );
  923. $this->_accessRulesArray[$hash]['authname'] = $val;
  924. }
  925. // ip/domain access rules
  926. if (preg_match('/^\s*Order\s+(Allow|Deny),\s*(Allow|Deny)\s*$/i', $l, $matches)) {
  927. $this->_accessRulesArray[$hash]['order'] = strtolower($matches[2]);
  928. }
  929. if (preg_match('/^\s*(allow|deny)\s+from\s+(.+)$/i', $l, $matches)) {
  930. foreach(explode(' ', $matches[2]) as $s) {
  931. $s = trim($s);
  932. if (empty($s)) {
  933. continue;
  934. }
  935. $rule = strtolower($matches[1]);
  936. $this->_accessRulesArray[$hash][$rule][] = $s;
  937. }
  938. }
  939. // error document rules
  940. if (preg_match('/^\s*ErrorDocument\s+401\s+(.+)$/i', $l, $matches)) {
  941. $val = trim($matches[1]);
  942. $this->_accessRulesArray[$hash]['errordocument401'] = $val;
  943. }
  944. $rows[] = $l;
  945. }
  946. $this->_fileDataArray[$hash] = $rows;
  947. }
  948. if ($filetype=='authuserfile' || $filetype=='authadminfile' || $filetype=='signupfile') {
  949. $users = array();
  950. foreach($lArray as $l) {
  951. if (preg_match('/^\s*#/', $l)) {
  952. continue;
  953. }
  954. $ldArray = split(':', $l);
  955. if (count($ldArray) < 2) {
  956. continue;
  957. }
  958. $data = array('name' => $ldArray[0],
  959. 'pass' => $ldArray[1],
  960. 'info' => isset($ldArray[2]) ? $ldArray[2] : null,
  961. 'email' => isset($ldArray[3]) ? $ldArray[3] : null);
  962. if ($filetype == 'signupfile') {
  963. $data['ts'] = isset($ldArray[4]) ? $ldArray[4]: null;
  964. $data['remoteaddr'] = isset($ldArray[5]) ? $ldArray[5] : null;
  965. $data['referer'] = implode(':', array_slice($ldArray, 6));
  966. }
  967. $users[] = $data;
  968. }
  969. $this->_fileDataArray[$hash] = $users;
  970. }
  971. if ($filetype == 'authgroupfile') {
  972. }
  973. return true;
  974. }
  975. /**
  976. * Set, Parse given file contents and optionaly Save it
  977. *
  978. * @access public
  979. * @param string $filetype
  980. * @param string $contents
  981. * @param bool|null $saveData
  982. * @param bool|null $saveRawData
  983. * @return bool
  984. */
  985. function setFileContentsByType( $filetype, $contents, $saveData=false, $saveRawData=false )
  986. {
  987. $path = $this->getPathByType( $filetype );
  988. if (false == $path) {
  989. $this->setError( $this->W('NOTDEFINED', $filetype) );
  990. return false;
  991. }
  992. $hash = md5( $path );
  993. $this->_fileContentsArray[$hash] = $contents;
  994. // parse contents
  995. if (false == $this->parseFileContentsByType( $filetype, $contents )) {
  996. return false;
  997. }
  998. if ($saveData) {
  999. if (false == $saveRawData) {
  1000. // build contents from parsed data
  1001. }
  1002. if (false == $this->saveFileByType( $filetype, $contents )) {
  1003. return false;
  1004. }
  1005. }
  1006. return true;
  1007. }
  1008. /***************************************************************************
  1009. * File Data Routes
  1010. **************************************************************************/
  1011. /**
  1012. * Return parsed data
  1013. *
  1014. * @access public
  1015. * @param string $filetype
  1016. * @return array
  1017. */
  1018. function getFileDataByType( $filetype )
  1019. {
  1020. $path = $this->getPathByType( $filetype );
  1021. if (false == $path) {
  1022. $this->setError( $this->W('NOTDEFINED', $filetype) );
  1023. return false;
  1024. }
  1025. $hash = md5( $path );
  1026. // not readed yet
  1027. if (!isset( $this->_fileDataArray[$hash] )) {
  1028. if (false == $this->readFileByType( $filetype )) {
  1029. return false;
  1030. }
  1031. }
  1032. return $this->_fileDataArray[$hash];
  1033. }
  1034. function getDefaultRecordsBytype( $filetype )
  1035. {
  1036. if ($filetype == 'authadminfile') {
  1037. $pass_raw = $this->_configArray['password'];
  1038. return array(array('name'=>$this->_configArray['login'],
  1039. //'pass'=>$this->encrypt_saltcrypt( $pass_raw, 'DES' ),
  1040. 'pass'=>$this->htcrypt($pass_raw, 'adminpass'),
  1041. 'pass_raw'=>$pass_raw,
  1042. 'info'=>'Administration',
  1043. 'email'=>'support'));
  1044. }
  1045. return array();
  1046. }
  1047. /**
  1048. * Update file record
  1049. *
  1050. * @access public
  1051. * @param string $filetype
  1052. * @param string|null $sortby
  1053. * @param int|null $limit
  1054. * @param int|null $offset
  1055. * @return array
  1056. */
  1057. function getRecordsByType( $filetype, $sortby=null, $limit=99999, $offset=0, $where=false )
  1058. {
  1059. $recArray = $this->getFileDataByType( $filetype );
  1060. if (false == $recArray) {
  1061. // return default values
  1062. return $this->getDefaultRecordsByType( $filetype );
  1063. }
  1064. if (false != $where && !is_array($where)) {
  1065. $where = array($where);
  1066. }
  1067. // TODO sortby
  1068. // limit, offset
  1069. $outArray = array();
  1070. for ($i=$offset; $i < count($recArray); ++$i) {
  1071. if ($i-$offset >= $limit) {
  1072. break;
  1073. }
  1074. $rec = $recArray[$i];
  1075. // filtering
  1076. if (false != $where) {
  1077. $valid = false;
  1078. foreach ($where as $field=>$patten) {
  1079. foreach($rec as $k=>$v) {
  1080. if (!is_int($field) && strcasecmp($field, $k) != 0) {
  1081. continue;
  1082. }
  1083. if (preg_match("/$patten/i", $v)) {
  1084. $valid = true;
  1085. break;
  1086. }
  1087. }
  1088. if ($valid) {
  1089. break;
  1090. }
  1091. }
  1092. if (!$valid) {
  1093. continue;
  1094. }
  1095. }
  1096. $outArray[] = $recArray[$i];
  1097. }
  1098. return $outArray;
  1099. }
  1100. function getTotalByType( $filetype, $where=false )
  1101. {
  1102. $recArray = $this->getFileDataByType( $filetype );
  1103. if (false == $recArray) {
  1104. if ($filetype == 'authadminfile') {
  1105. return 1;
  1106. }
  1107. return 0;
  1108. }
  1109. if (false == $where) {
  1110. return count($recArray);
  1111. }
  1112. if (!is_array($where)) {
  1113. $where = array($where);
  1114. }
  1115. $count = 0;
  1116. foreach($recArray as $rec) {
  1117. $valid = false;
  1118. foreach ($where as $field=>$patten) {
  1119. foreach($rec as $k=>$v) {
  1120. if (!is_int($field) && strcasecmp($field, $k) != 0) {
  1121. continue;
  1122. }
  1123. if (preg_match("/$patten/i", $v)) {
  1124. $valid = true;
  1125. break;
  1126. }
  1127. }
  1128. if ($valid) {
  1129. break;
  1130. }
  1131. }
  1132. if (!$valid) {
  1133. continue;
  1134. }
  1135. $count++;
  1136. }
  1137. return $count;
  1138. }
  1139. /**
  1140. * Fetch record by Id
  1141. *
  1142. * @access public
  1143. * @param string $filetype
  1144. * @param string $recordId
  1145. * @param bool $checkDefault
  1146. * @return string|array|bool
  1147. */
  1148. function fetchRecordByType( $filetype, $recordId, $checkDefault=false )
  1149. {
  1150. $dataArray = $this->getFileDataByType( $filetype );
  1151. if (false == $dataArray || count($dataArray) < 1) {
  1152. if (false == $checkDefault) {
  1153. return false;
  1154. }
  1155. $dataArray = $this->getDefaultRecordsByType( $filetype );
  1156. }
  1157. if (is_null($recordId)) {
  1158. // reset first record for authadminfile
  1159. if ($filetype == 'authadminfile') {
  1160. return $this->getDefaultRecordsByType( $filetype );
  1161. }
  1162. return false;
  1163. }
  1164. $found = false;
  1165. foreach( $dataArray as $rec ) {
  1166. if ($filetype == 'accessfile') {
  1167. if ($recordId == 'errordocument401') {
  1168. if (preg_match('/^\s*ErrorDocument\s+401\s+/i', $rec)) {
  1169. $found = $rec;
  1170. break;
  1171. }
  1172. } else if (preg_match('/^\s*'.$recordId.'(\s+.+)?\s*$/i', $rec)) {
  1173. $found = $rec;
  1174. break;
  1175. }
  1176. continue;
  1177. }
  1178. if (isset($rec['name']) && strcmp($recordId, $rec['name'])==0) {
  1179. $found = $rec;
  1180. break;
  1181. }
  1182. }
  1183. return $found;
  1184. }
  1185. /**
  1186. * Check record by Id
  1187. *
  1188. * @access public
  1189. * @param string $filetype
  1190. * @param string $recordId
  1191. * @return bool
  1192. */
  1193. function isRecordByType( $filetype, $recordId )
  1194. {
  1195. $rec = $this->fetchRecordByType($filetype, $recordId);
  1196. return $rec == false ? false : true;
  1197. }
  1198. /**
  1199. * Update record in file
  1200. *
  1201. * @access public
  1202. * @param string $filetype
  1203. * @param string $recordId
  1204. * @param array data
  1205. * @return bool
  1206. */
  1207. function updateRecordByType( $filetype, $recordId, $data )
  1208. {
  1209. $path = $this->getPathByType( $filetype );
  1210. if (false == $path) {
  1211. $this->setError( $this->W('NOTDEFINED', $filetype) );
  1212. return false;
  1213. }
  1214. $hash = md5( $path );
  1215. if (!is_array($this->_fileDataArray[$hash])) {
  1216. $this->_fileDataArray[$hash] = null;
  1217. }
  1218. if ($filetype == 'accessfile') {
  1219. $found = false;
  1220. $recordId = strtolower($recordId);
  1221. foreach ($this->_fileDataArray[$hash] as $id=>$rec) {
  1222. $rec = trim($rec);
  1223. $args = isset($data[$recordId]) ? $data[$recordId] : '';
  1224. if ($recordId == 'errordocument401') {
  1225. if (preg_match('/^(\s*ErrorDocument\s+401)\s+/i', $rec, $matches)) {
  1226. if (!isset($data)) {
  1227. unset( $this->_fileDataArray[$hash][$id] );
  1228. continue;
  1229. }
  1230. $this->_fileDataArray[$hash][$id] = $matches[1] . ' ' . $args;
  1231. }
  1232. // remove all allow or deny commands
  1233. } else if (preg_match('/^\s*'.$recordId.'\s+from\s+.*$/i', $rec)) {
  1234. unset( $this->_fileDataArray[$hash][$id] );
  1235. } else if (preg_match('/^(\s*'.$recordId.')(.*)$/i', $rec, $matches)) {
  1236. if (!isset($data)) {
  1237. unset( $this->_fileDataArray[$hash][$id] );
  1238. continue;
  1239. }
  1240. if ($recordId == 'authname') {
  1241. $this->_fileDataArray[$hash][$id] = $matches[1] . ' "' . addSlashes($args) . '"';
  1242. } else if ($recordId == 'authuserfile') {
  1243. $this->_fileDataArray[$hash][$id] = $matches[1] . ' ' . $args;
  1244. } else if ($recordId == 'authtype') {
  1245. $this->_fileDataArray[$hash][$id] = $matches[1] . ' basic';
  1246. } else if ($recordId == 'order') {
  1247. $this->_fileDataArray[$hash][$id] = 'Order ' . ($args=='deny' ? 'Allow,Deny' : 'Deny,Allow');
  1248. }
  1249. $found = true;
  1250. break;
  1251. }
  1252. }
  1253. // special case: allow or deny commands
  1254. if ($recordId == 'allow' || $recordId == 'deny') {
  1255. foreach($data as $item) {
  1256. $this->_fileDataArray[$hash][] = $recordId . ' from ' . $item;
  1257. }
  1258. }
  1259. return $found;
  1260. }
  1261. // other types
  1262. foreach ($this->_fileDataArray[$hash] as $id=>$rec) {
  1263. if (is_null($recordId) || isset($rec['name']) && strcmp($recordId, $rec['name'])==0) {
  1264. if (is_null($data)) {
  1265. unset( $this->_fileDataArray[$hash][$id] );
  1266. } else if (is_array($data)) {
  1267. foreach ($data as $k=>$v) {
  1268. $this->_fileDataArray[$hash][$id][$k] = $v;
  1269. }
  1270. }
  1271. break;
  1272. }
  1273. }
  1274. return true;
  1275. }
  1276. /**
  1277. * Update file record
  1278. *
  1279. * @access public
  1280. * @param string $filetype
  1281. * @param array $data
  1282. * @param string $curRecordId
  1283. * @param bool|null $saveFile
  1284. * @param bool|null $saveForce
  1285. * @return bool
  1286. */
  1287. function setRecordByType( $filetype, $curRecordId, $data, $saveFile=false, $saveForce=false )
  1288. {
  1289. $path = $this->getPathByType( $filetype );
  1290. if (false == $path) {
  1291. $this->setError( $this->W('NOTDEFINED', $filetype) );
  1292. return false;
  1293. }
  1294. $hash = md5( $path );
  1295. if (false != $this->isRecordByType( $filetype, $curRecordId )) {
  1296. // replaceing
  1297. $this->updateRecordByType( $filetype, $curRecordId, $data );
  1298. } else if (is_array($data)) {
  1299. // inserting
  1300. if ($filetype == 'accessfile') {
  1301. $args = isset($data[$curRecordId]) ? $data[$curRecordId] : '';
  1302. $hasAddedBy = false;
  1303. foreach( $this->_fileDataArray[$hash] as $rec) {
  1304. if (preg_match('/^# added by authman/i', $rec)) {
  1305. $hasAddedBy = true;
  1306. }
  1307. }
  1308. if (!$hasAddedBy) {
  1309. $this->_fileDataArray[$hash][] = "# Added By Authman";
  1310. }
  1311. if ($curRecordId == 'authname') {
  1312. $this->_fileDataArray[$hash][] = 'AuthName "' . $args . '"';
  1313. } else if ($curRecordId == 'authtype') {
  1314. $this->_fileDataArray[$hash][] = 'AuthType ' . $args;
  1315. } else if ($curRecordId == 'require') {
  1316. $this->_fileDataArray[$hash][] = 'require ' . $args;
  1317. } else if ($curRecordId == 'authuserfile') {
  1318. $this->_fileDataArray[$hash][] = 'AuthUserFile ' . $args;
  1319. } else if ($curRecordId == 'errordocument401') {
  1320. $this->_fileDataArray[$hash][] = 'ErrorDocument 401 ' . $args;
  1321. } else if ($curRecordId == 'order') {
  1322. $this->_fileDataArray[$hash][] = 'Order ' . ($args=='deny' ? 'Allow,Deny' : 'Deny,Allow');
  1323. } else if ($curRecordId == 'allow' || $curRecordId == 'deny') {
  1324. foreach($data as $item) {
  1325. $this->_fileDataArray[$hash][] = $curRecordId . ' from ' . $item;
  1326. }
  1327. } else {
  1328. $this->_fileDataArray[$hash][] = '# '. $curRecordId . ' "' . $args . '"';
  1329. }
  1330. // other files types
  1331. } else {
  1332. $this->_fileDataArray[$hash][] = $data;
  1333. }
  1334. }
  1335. if ($saveFile) {
  1336. $strerr = null;
  1337. // save parsed data
  1338. if (false == $this->saveFileByType( $filetype, false )) {
  1339. $strerr = $this->getError();
  1340. }
  1341. $this->readFileByType( $filetype );
  1342. if (isset($strerr)) {
  1343. $this->setError($strerr);
  1344. return false;
  1345. }
  1346. }
  1347. return true;
  1348. }
  1349. /**
  1350. * Clear all records from the file
  1351. *
  1352. * @access public
  1353. * @param string $filetype
  1354. * @param bool|null $saveFile
  1355. * @return bool
  1356. */
  1357. function clearAllRecordsByType( $filetype, $saveFile=false )
  1358. {
  1359. $path = $this->getPathByType( $filetype );
  1360. if (false == $path) {
  1361. $this->setError( $this->W('NOTDEFINED', $filetype) );
  1362. return false;
  1363. }
  1364. $hash = md5( $path );
  1365. $this->_fileDataArray[$hash] = array();
  1366. if ($saveFile) {
  1367. $strerr = null;
  1368. // save _RAW_ data
  1369. if (false == $this->saveFileByType( $filetype, true, '' )) {
  1370. $strerr = $this->getError();
  1371. }
  1372. $this->readFileByType( $filetype );
  1373. if (isset($strerr)) {
  1374. $this->setError($strerr);
  1375. return false;
  1376. }
  1377. }
  1378. return true;
  1379. }
  1380. function getAccessRuleByType( $filetype, $ruleName )
  1381. {
  1382. $hash = md5( $this->getPathByType( $filetype ) );
  1383. if (!isset($this->_accessRulesArray[$hash])) {
  1384. return false;
  1385. }
  1386. $ruleName = strtolower($ruleName);
  1387. if (!isset($this->_accessRulesArray[$hash][$ruleName])) {
  1388. return false;
  1389. }
  1390. return $this->_accessRulesArray[$hash][$ruleName];
  1391. }
  1392. /***************************************************************************
  1393. *
  1394. **************************************************************************/
  1395. /**
  1396. * Get template list
  1397. *
  1398. * @access public
  1399. * @return array
  1400. */
  1401. function getTemplates()
  1402. {
  1403. $this->_tplsArray = array();
  1404. $tplPath = $this->_basePath . DIRECTORY_SEPARATOR . 'templates';
  1405. $dh = @opendir( $tplPath );
  1406. if (false == $dh) {
  1407. return $this->_tplsArray;
  1408. }
  1409. while ($e = readdir($dh)) {
  1410. if ($e == '.' || $e == '..') {
  1411. continue;
  1412. }
  1413. if (!preg_match('/^(.+)\.tpl(\.dist)?$/i', $e, $matches)) {
  1414. continue;
  1415. }
  1416. $tplId = $matches[1];
  1417. $tplDefault = isset($matches[2]) && $matches[2] == '.dist';
  1418. $filePath = $tplPath . DIRECTORY_SEPARATOR . $e;
  1419. $fh = @fopen($filePath, 'r');
  1420. if (false == $fh) {
  1421. continue;
  1422. }
  1423. $data = array();
  1424. while ($l = fgets($fh)) {
  1425. $data[] = $l;
  1426. }
  1427. @fclose($fh);
  1428. $role = 'undefinied';
  1429. if (preg_match('/^(useradd|useredit|userdel|userfgt|userrcv|memberaa|memberdel|memberreq)$/i', $tplId, $matches)) {
  1430. $role = strtolower($matches[1]);
  1431. }
  1432. $tArray = array('path'=>$filePath,
  1433. 'id'=>$tplId,
  1434. 'role'=>$role,
  1435. 'name'=>trim($data[0]),
  1436. 'type'=>( trim($data[1]) == 'html' ? 'html' : 'plaintext' ),
  1437. 'subject'=>trim($data[2]),
  1438. 'contents'=>join('', array_slice($data, 3)) );
  1439. if (!$tplDefault || !array_key_exists($tplId, $this->_tplsArray)) {
  1440. $this->_tplsArray[ $tplId ] = $tArray;
  1441. }
  1442. }
  1443. closedir($dh);
  1444. return $this->_tplsArray;
  1445. }
  1446. function getTemplateById( $id )
  1447. {
  1448. if (!isset($id) || $id=='') {
  1449. return false;
  1450. }
  1451. $templates = $this->getTemplates();
  1452. if (false==$templates || !isset($templates[$id])) {
  1453. return false;
  1454. }
  1455. return $templates[$id];
  1456. }
  1457. function getTemplateByRole( $role )
  1458. {
  1459. $res = false;
  1460. $templates = $this->getTemplates();
  1461. foreach($templates as $id=>$tpl) {
  1462. if ($tpl['role'] == $role) {
  1463. $res = $tpl;
  1464. }
  1465. }
  1466. return $res;
  1467. }
  1468. function saveTemplateAs( $id, $data, $force=false )
  1469. {
  1470. if (!isset($id) || $id=='' || !is_array($data)) {
  1471. $this->setError( $this->E('INVALIDREQUEST') );
  1472. return false;
  1473. }
  1474. // Saving in DEMO mode is disabled
  1475. if ($this->isDemo()) {
  1476. $this->setError( $this->W('DEMOISON') );
  1477. return false;
  1478. }
  1479. $path = $this->_basePath . DIRECTORY_SEPARATOR . 'templates';
  1480. if (!is_dir($path)) {
  1481. if (false == @mkdir($path, 0755)) {
  1482. $this->setError( $this->E('MKDIRFAILED', $path) );
  1483. return false;
  1484. }
  1485. $denyPath = $path . DIRECTORY_SEPARATOR
  1486. . $this->_configArray['access_file'];
  1487. $this->writeDenyFile( $denyPath );
  1488. }
  1489. $id = $this->getNormalizedPath( $id );
  1490. $filePath = $path . $id . '.tpl';
  1491. if (is_file($filePath) && false == $force) {
  1492. $this->setError( $this->E('FILEEXISTS', $filePath) );
  1493. return false;
  1494. }
  1495. if (is_file($filePath) && !is_writable($filePath)) {
  1496. $this->setError( $this->W('FILEWRITABLE') );
  1497. return false;
  1498. }
  1499. $fh = @fopen($filePath, 'w');
  1500. if (false == $fh) {
  1501. $this->setError( $this->E('FILEOPENFAILED', $filePath) );
  1502. return false;
  1503. }
  1504. @fwrite($fh, $data['name'] . "\n");
  1505. @fwrite($fh, $data['type'] . "\n");
  1506. @fwrite($fh, $data['subject'] . "\n");
  1507. @fwrite($fh, $data['contents'] . "\n");
  1508. @fclose($fh);
  1509. return true;
  1510. }
  1511. /**
  1512. * @desc Delete e-mail template
  1513. *
  1514. * @access public
  1515. * @param string $id
  1516. * @param bool $force
  1517. * @return bool
  1518. */
  1519. function deleteTemplate( $id, $force=false )
  1520. {
  1521. // Deleting in DEMO mode is disabled
  1522. if ($this->isDemo()) {
  1523. $this->setError( $this->W('DEMOISON') );
  1524. return false;
  1525. }
  1526. // Check if
  1527. $template = $this->getTemplateById( $id );
  1528. if (false == $template) {
  1529. $this->setError( $this->E('TPLNOTFOUND', $id) );
  1530. return false;
  1531. }
  1532. if ($force == false) {
  1533. if ($template['role'] != 'undefinied') {
  1534. $this->setError( $this->E('TPLISSYSTEM') );
  1535. return false;
  1536. }
  1537. }
  1538. $path = $this->_basePath . DIRECTORY_SEPARATOR . 'templates';
  1539. $filePath = $path . DIRECTORY_SEPARATOR . $id . '.tpl';
  1540. if (!is_file($filePath)) {
  1541. $this->setError( $this->E('NOSUCHFILE', $filePath) );
  1542. return false;
  1543. }
  1544. if (false == @unlink($filePath)) {
  1545. $this->setError( $this->E('FILEDELFAILED', $filePath) );
  1546. return false;
  1547. }
  1548. return true;
  1549. }
  1550. /***************************************************************************
  1551. * E-mail routes
  1552. **************************************************************************/
  1553. /**
  1554. * Send e-mail to the user
  1555. *
  1556. * @access public
  1557. * @param string|array $templateId
  1558. * @param array $userArray
  1559. * @return bool
  1560. */
  1561. function sendMail( $templateId, $userArray )
  1562. {
  1563. if (false == $this->hasFeature('PHPMailer')) {
  1564. $this->setError( 'SendMail: ' . $this->W('SENDMAILFAIL_INSTALLPHPMAILER'));
  1565. return false;
  1566. }
  1567. // no spam here
  1568. if ($this->isDemo()) {
  1569. $this->setError( 'SendMail: ' . $this->W('DEMOISON') );
  1570. return false;
  1571. }
  1572. if (is_array($templateId)) {
  1573. $tplArray = $templateId;
  1574. $templateId = 'manual';
  1575. } else {
  1576. $tplArray = $this->getTemplateById( $templateId );
  1577. if (false == $tplArray) {
  1578. $this->setError( 'SendMail: ' . $this->E('INCORRECTARGS') . ' [template]' );
  1579. return false;
  1580. }
  1581. }
  1582. if (!isset($userArray['email']) || $userArray['email'] == '') {
  1583. $this->setError( 'SendMail: ' . $this->E('INCORRECTARGS') . ' [email]' );
  1584. return false;
  1585. }
  1586. $args = array('PROTECTEDURL'=> $this->getUrlByType('protected', true),
  1587. 'BASEURL' => $this->getUrlByType('base', true),
  1588. 'MEMBERURL' => $this->getUrlByType('login', true),
  1589. 'REMOTEADDR' => $_SERVER['REMOTE_ADDR'],
  1590. 'DATETIME' => gmdate('D dS \of M Y H:i:s e') );
  1591. list($admin) = $this->getRecordsByType( 'authadminfile', null, 1, 0 );
  1592. $args['ADMINREALNAME'] = $admin['info'] != '' ? $admin['info'] : "Administrator";
  1593. $args['ADMINEMAIL'] = $admin['email'] != '' ? $admin['email'] : "postmaster@localhost";
  1594. foreach($userArray as $k=>$v) {
  1595. $kk = 'USER' . strtoupper($k);
  1596. $args[$kk] = $v;
  1597. }
  1598. $args['USERREALNAME'] = isset($userArray['info']) && $userArray['info'] != ''
  1599. ? $userArray['info'] : $userArray['name'];
  1600. $args['USERPASSWORD'] = isset($userArray['pass_raw']) && $userArray['pass_raw'] != '' ? $userArray['pass_raw'] : '[ENCRYPTED: '. $userArray['pass'] .']';
  1601. $subject = $tplArray['subject'];
  1602. $body = $tplArray['contents'];
  1603. foreach(array('subject', 'body') as $vname) {
  1604. foreach( $args as $k=>$v ) {
  1605. $$vname = str_replace('%'.$k.'%', $v, $$vname);
  1606. }
  1607. }
  1608. // sending
  1609. include_once( $this->getPathByType('PHPMailer') );
  1610. $mail = new PHPMailer();
  1611. $mail->CharSet = "UTF-8";
  1612. // from administrator
  1613. $mail->FromName = $args['ADMINREALNAME'];
  1614. $mail->From = $args['ADMINEMAIL'];
  1615. $mail->AddReplyTo($args['ADMINEMAIL'], $args['ADMINREALNAME']);
  1616. $isHtml = $tplArray['type'] == 'html';
  1617. if ($templateId=='memberdel' || $templateId=='memberaa') {
  1618. $mail->AddAddress($args['ADMINEMAIL'], $args['ADMINREALNAME']);
  1619. } else {
  1620. if (!isset($args['USEREMAIL']) || $args['USEREMAIL']=='') {
  1621. if ($isHtml) {
  1622. $body = '<p><strong>USER ' . $userArray['name'] . ' have not E-mail address</strong></p><br />' . $body;
  1623. } else {
  1624. $body = 'USER ' . $userArray['name'] . " have not E-mail address\n" . $body;
  1625. }
  1626. $mail->AddAddress($args['ADMINEMAIL'], $args['ADMINREALNAME']);
  1627. } else {
  1628. $mail->AddAddress($args['USEREMAIL'], $args['USERREALNAME']);
  1629. }
  1630. }
  1631. $mail->Subject = $subject;
  1632. $mail->Body = $body;
  1633. if ($isHtml) {
  1634. $mail->IsHTML( true );
  1635. $mail->AltBody = "To view the message, please use an HTML compatible email viewer!";
  1636. }
  1637. if (false == $mail->Send()) {
  1638. $this->setError( 'SendMail: ' . $mail->ErrorInfo );
  1639. return false;
  1640. }
  1641. return true;
  1642. }
  1643. function hasFeature( $feature )
  1644. {
  1645. $ln = strtolower($feature);
  1646. if ($ln == 'phpmailer' || $ln == 'tinymcejs' || $ln = 'magpierss') {
  1647. $filePath = $this->getPathByType( $ln );
  1648. if (!is_file($filePath) || !is_readable($filePath)) {
  1649. return false;
  1650. }
  1651. return true;
  1652. }
  1653. return true;
  1654. }
  1655. /***************************************************************************
  1656. * Messages/Warnings/Errors Reporting
  1657. **************************************************************************/
  1658. /**
  1659. * Messages wrapper
  1660. *
  1661. * @access public
  1662. * @return string
  1663. */
  1664. function M()
  1665. {
  1666. $args = func_get_args();
  1667. return $this->getMessage( 'messages', $args );
  1668. }
  1669. /**
  1670. * Warnings wrapper
  1671. *
  1672. * @access public
  1673. * @return string
  1674. */
  1675. function W()
  1676. {
  1677. $args = func_get_args();
  1678. return $this->getMessage( 'warnings', $args );
  1679. }
  1680. /**
  1681. * Errors wrapper
  1682. *
  1683. * @access public
  1684. * @return string
  1685. */
  1686. function E()
  1687. {
  1688. $args = func_get_args();
  1689. return $this->getMessage( 'errors', $args );
  1690. }
  1691. /**
  1692. * Return formated message
  1693. *
  1694. * @access private
  1695. * @param string $type
  1696. * @param array $args
  1697. * @return string
  1698. */
  1699. function getMessage( $type, $args )
  1700. {
  1701. $fmt = strtoupper(array_shift($args));
  1702. if (isset($this->_langArray[$type]) && isset($this->_langArray[$type][$fmt])) {
  1703. $s = vsprintf( $this->_langArray[$type][$fmt], $args);
  1704. } else {
  1705. $s = '[' . $type . ': ' . $fmt;
  1706. if (count($args)) {
  1707. $s .= ':';
  1708. foreach ($args as $t) {
  1709. $s .= ' ' . $t;
  1710. }
  1711. }
  1712. $s .= ']';
  1713. }
  1714. return $s;
  1715. }
  1716. /**
  1717. * Set error message
  1718. *
  1719. * @access protected
  1720. * @param string|null
  1721. */
  1722. function setError( $error=null )
  1723. {
  1724. $this->_error = $error;
  1725. if (!isset($error)) {
  1726. return;
  1727. }
  1728. if (isset($php_errormsg))
  1729. $this->_error .= ': ' . $php_errormsg;
  1730. return;
  1731. }
  1732. /**
  1733. * Return true if error string is set
  1734. *
  1735. * @access public
  1736. * @return bool
  1737. */
  1738. function isError()
  1739. {
  1740. return $this->_error == '' ? false : true;
  1741. }
  1742. /**
  1743. * Get error message
  1744. *
  1745. * @access public
  1746. * @return string
  1747. */
  1748. function getError()
  1749. {
  1750. if (!isset(

Large files files are truncated, but you can click here to view the full file