PageRenderTime 27ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/www/phpbb.store.php

https://gitlab.com/pirati.cz/simpleid
PHP | 451 lines | 210 code | 77 blank | 164 comment | 51 complexity | 14d44ccfe13de50089c39ded4a1d53f0 MD5 | raw file
  1. <?php
  2. /*
  3. * SimpleID
  4. *
  5. * Copyright (C) Kelvin Mo 2007-9
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2 of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public
  18. * License along with this program; if not, write to the Free
  19. * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. *
  21. * $Id$
  22. */
  23. /**
  24. * Functions for persistent storage via the file system.
  25. *
  26. * In general, there are three different sets of data which SimpleID needs
  27. * to store:
  28. *
  29. * - transient data (e.g. OpenID associations, sessions, auto-login)
  30. * - application data (e.g. salt for form tokens)
  31. * - user data (e.g. user names, passwords and settings)
  32. *
  33. * Prior to version 0.7, both transient data and application data are stored
  34. * using {@link cache.inc}. From version 0.7, application data are now
  35. * stored separately from the cache.
  36. *
  37. * Prior to version 0.7, user data is only stored in the identity file, to which
  38. * SimpleID cannot write. This means that if the user wishes to change a setting,
  39. * he or she will need to edit the identity file manually. Other user settings
  40. * (e.g. RP preferences) are stored using {@link cache.inc}
  41. *
  42. * From version 0.7, user data is stored in two files, one is the identity
  43. * file, the other is the user store file, which SimpleID can write.
  44. *
  45. * @package simpleid
  46. * @filesource
  47. */
  48. /**
  49. * This variable is a cache of SimpleID's application settings. It is populated
  50. * progressively as {@link store_get()} is called.
  51. *
  52. * @global array $simpleid_settings
  53. */
  54. $simpleid_settings = array();
  55. function _clean_username($uid) {
  56. return trim(strtolower($uid));
  57. }
  58. /**
  59. * Returns whether the user name exists in the user store.
  60. *
  61. * @param string $uid the name of the user to check
  62. * @return bool whether the user name exists
  63. */
  64. function store_user_exists($uid) {
  65. $clean_uid = _clean_username($uid);
  66. if (_store_is_valid_name($clean_uid)) {
  67. $q = _store_phpbb_sock()->prepare("SELECT COUNT(*) FROM phpbb_users JOIN phpbb_user_group ON (phpbb_users.user_id = phpbb_user_group.user_id) JOIN phpbb_groups ON (phpbb_user_group.group_id = phpbb_groups.group_id) WHERE (group_name = 'Celostatni forum' or group_name = 'Registrovani priznivci') AND username_clean = ? AND user_type=0");
  68. $q->execute(array($clean_uid));
  69. return ( $q->fetchColumn() > 0);
  70. } else {
  71. return false;
  72. }
  73. }
  74. /**
  75. * Loads user data for a specified user name.
  76. *
  77. * The user name must exist. You should check whether the user name exists with
  78. * the {@link store_user_exists()} function
  79. *
  80. * @param string $uid the name of the user to load
  81. * @return mixed data for the specified user
  82. */
  83. function store_user_load($uid) {
  84. $clean_uid = _clean_username($uid);
  85. if (!store_user_exists($uid)) return array();
  86. $q = _store_phpbb_sock()->prepare("SELECT username as nickname, CONCAT(REPLACE(LOWER(username_clean),' ','.'),'@pirati.cz') as email,user_lang as language, phpbb_profile_fields_data.pf_fullname as fullname, user_birthday as dob FROM phpbb_users JOIN phpbb_profile_fields_data ON (phpbb_users.user_id = phpbb_profile_fields_data.user_id)JOIN phpbb_user_group ON (phpbb_users.user_id = phpbb_user_group.user_id) JOIN phpbb_groups ON (phpbb_user_group.group_id = phpbb_groups.group_id) WHERE (group_name = 'Celostatni forum' or group_name = 'Registrovani priznivci') AND username_clean = ? AND user_type=0");
  87. $q->execute(array($clean_uid));
  88. $sreg = $q->fetch(PDO::FETCH_ASSOC);
  89. $uid = $sreg['nickname'];
  90. $store_file = SIMPLEID_STORE_DIR . "/$uid.usrstore";
  91. if (file_exists($store_file)) {
  92. $data = unserialize(file_get_contents($store_file));
  93. } else {
  94. $data = array();
  95. }
  96. $data['sreg'] = $sreg;
  97. $data['identity'] = preg_replace('/^https/','https', simpleid_url("user/" . rawurlencode($data['sreg']['nickname'])));
  98. if (preg_match('/^\s*(\d+)\s*-\s*(\d+)\s*-(\d+)$/', $data['sreg']['dob'], $m)) {
  99. $data['sreg']['dob'] = sprintf("%04d-%02d-%02d", $m[3], $m[2], $m[1]);
  100. } else {
  101. unset($data['sreg']['dob']);
  102. }
  103. $data['sreg']['fullname'] = html_entity_decode($data['sreg']['fullname']);
  104. $data['uid'] = $uid;
  105. return $data;
  106. }
  107. /**
  108. * Returns the time which a user's data has been updated.
  109. *
  110. * The user name must exist. You should check whether the user name exists with
  111. * the {@link store_user_exists()} function.
  112. *
  113. * The time returned can be based on the identity file,
  114. * the user store file, or the latter of the two.
  115. *
  116. * @param string $uid the name of the user to obtain the update time
  117. * @param string $type one of: 'identity' (identity file), 'usrstore' (user store
  118. * file) or NULL (latter of the two)
  119. * @return int the updated time
  120. */
  121. function store_user_updated_time($uid, $type = NULL) {
  122. $clean_uid = _clean_username($uid);
  123. if (!_store_is_valid_name($uid)) return NULL;
  124. $q = _store_phpbb_sock()->prepare("SELECT user_passchg FROM phpbb_users WHERE username_clean = ? AND user_type=0");
  125. $q->execute(array($clean_uid));
  126. $identity_time = $q->fetchColumn();
  127. $store_file = SIMPLEID_STORE_DIR . "/$uid.usrstore";
  128. if (file_exists($store_file)) {
  129. $store_time = filemtime($store_file);
  130. } else {
  131. $store_time = NULL;
  132. }
  133. if ($type == 'identity') {
  134. return $identity_time;
  135. } elseif ($type == 'usrstore') {
  136. return $store_time;
  137. } elseif ($type == NULL) {
  138. return ($identity_time > $store_time) ? $identity_time : $store_time;
  139. } else {
  140. return NULL;
  141. }
  142. }
  143. /**
  144. * Finds the user name from a specified OpenID Identity URI.
  145. *
  146. * @param string $identity the Identity URI of the user to load
  147. * @return string the user name for the Identity URI, or NULL if no user has
  148. * the specified Identity URI
  149. */
  150. function store_get_uid($identity) {
  151. $r = NULL;
  152. if (!preg_match('/\/([a-zA-Z .]+)$/', rawurldecode(parse_url($identity, PHP_URL_PATH)), $m))
  153. return NULL;
  154. if (preg_replace('/^https/','https', simpleid_url("user/" . rawurlencode($m[1]))) !== $identity)
  155. return NULL;
  156. return $m[1];
  157. }
  158. /**
  159. * Finds the user name from a specified client SSL certificate string.
  160. *
  161. * The client SSL certificate string comprises the certificate's serial number
  162. * (in capitals hex notation) and the distinguished name of the certificate's issuer
  163. * (with components joined using slashes), joined using a semi-colon.
  164. *
  165. *
  166. * @param string $cert the client SSL certificate string of the user to load
  167. * @return string the user name matching the client SSL certificate string, or NULL if no user has
  168. * client SSL certificate string
  169. */
  170. function store_get_uid_from_cert($cert) {
  171. return NULL;
  172. }
  173. /**
  174. * Saves user data for a specific user name.
  175. *
  176. * This data is stored in the user store file.
  177. *
  178. * @param string $uid the name of the user
  179. * @param array $data the data to save
  180. * @param array $exclude an array of keys to exclude from the user store file.
  181. * These are generally keys which are stored in the identity file.
  182. *
  183. * @since 0.7
  184. */
  185. function store_user_save($uid, $data, $exclude = array()) {
  186. //$uid = _clean_username($uid);
  187. foreach ($exclude as $key) {
  188. if (isset($data[$key])) unset($data[$key]);
  189. }
  190. if (!_store_is_valid_name($uid)) {
  191. trigger_error("Invalid user name for filesystem store", E_USER_ERROR);
  192. return;
  193. }
  194. $store_file = SIMPLEID_STORE_DIR . "/$uid.usrstore";
  195. $file = fopen($store_file, 'w');
  196. fwrite($file, serialize($data));
  197. fclose($file);
  198. }
  199. /**
  200. * Loads an application setting.
  201. *
  202. * @param string $name the name of the setting to return
  203. * @param mixed $default the default value to use if this variable has never been set
  204. * @return mixed the value of the setting
  205. *
  206. */
  207. function store_get($name, $default = NULL) {
  208. global $simpleid_settings;
  209. if (!_store_is_valid_name($name)) return $default;
  210. if (!isset($simpleid_settings[$name])) {
  211. $setting_file = SIMPLEID_STORE_DIR . "/$name.setting";
  212. if (file_exists($setting_file)) {
  213. $simpleid_settings[$name] = unserialize(file_get_contents($setting_file));
  214. } else {
  215. return $default;
  216. }
  217. }
  218. return $simpleid_settings[$name];
  219. }
  220. /**
  221. * Saves an application setting.
  222. *
  223. * @param string $name the name of the setting to save
  224. * @param mixed $value the value of the setting
  225. *
  226. */
  227. function store_set($name, $value) {
  228. global $simpleid_settings;
  229. if (!_store_is_valid_name($name)) {
  230. trigger_error("Invalid setting name for filesystem store", E_USER_ERROR);
  231. return;
  232. }
  233. $simpleid_settings[$name] = $value;
  234. $setting_file = SIMPLEID_STORE_DIR . "/$name.setting";
  235. $file = fopen($setting_file, 'w');
  236. fwrite($file, serialize($value));
  237. fclose($file);
  238. }
  239. /**
  240. * Deletes an application setting.
  241. *
  242. * @param string $name the name of the setting to delete
  243. *
  244. */
  245. function store_del($name) {
  246. global $simpleid_settings;
  247. if (!_store_is_valid_name($name)) {
  248. trigger_error("Invalid setting name for filesystem store", E_USER_ERROR);
  249. return;
  250. }
  251. if (isset($simpleid_settings[$name])) unset($simpleid_settings[$name]);
  252. $setting_file = SIMPLEID_STORE_DIR . "/$name.setting";
  253. if (file_exists($setting_file)) unlink($setting_file);
  254. }
  255. function store_user_verify_credentials($uid, $credentials)
  256. {
  257. $clean_uid = _clean_username($uid);
  258. $q = _store_phpbb_sock()->prepare("SELECT user_password FROM phpbb_users JOIN phpbb_user_group ON (phpbb_users.user_id = phpbb_user_group.user_id) JOIN phpbb_groups ON (phpbb_user_group.group_id = phpbb_groups.group_id) WHERE (group_name = 'Celostatni forum' or group_name = 'Registrovani priznivci') AND username_clean = ? AND user_type=0");
  259. $q->execute(array($clean_uid));
  260. if (!($hash = $q->fetchColumn())) {
  261. return false;
  262. }
  263. if (strlen($hash) != 34) {
  264. return false;
  265. }
  266. $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  267. return (_phpbb_hash_crypt_private($credentials['pass'], $hash, $itoa64) === $hash) ? true : false;
  268. }
  269. /**
  270. * Determines whether a name is a valid name for use with this store.
  271. *
  272. * For file system storage, a name is not valid if it contains either a
  273. * directory separator (i.e. / or \).
  274. *
  275. * @param string $name the name to check
  276. * @return boolean whether the name is valid for use with this store
  277. *
  278. */
  279. function _store_is_valid_name($name) {
  280. return preg_match('!\A[^/\\\\]*\z!', $name);
  281. }
  282. function _store_phpbb_sock() {
  283. $arr = parse_ini_file(__DIR__."/../config/phpbb.store.ini");
  284. $dsn = "mysql:host=".$arr['dbhost'].";dbname=".$arr['dbbase'].";charset=utf8";
  285. static $sock = null;
  286. if ($sock === null) {
  287. $sock = new PDO($dsn, $arr['dbuser'], $arr['dbpass'], array(
  288. PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
  289. PDO::ATTR_PERSISTENT => true,
  290. ));
  291. }
  292. return $sock;
  293. }
  294. /**
  295. * The crypt function/replacement
  296. * @copyright (c) 2005 phpBB Group
  297. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  298. *
  299. */
  300. function _phpbb_hash_crypt_private($password, $setting, &$itoa64)
  301. {
  302. $output = '*';
  303. // Check for correct hash
  304. if (substr($setting, 0, 3) != '$H$' && substr($setting, 0, 3) != '$P$') {
  305. return $output;
  306. }
  307. $count_log2 = strpos($itoa64, $setting[3]);
  308. if ($count_log2 < 7 || $count_log2 > 30) {
  309. return $output;
  310. }
  311. $count = 1 << $count_log2;
  312. $salt = substr($setting, 4, 8);
  313. if (strlen($salt) != 8) {
  314. return $output;
  315. }
  316. /**
  317. * We're kind of forced to use MD5 here since it's the only
  318. * cryptographic primitive available in all versions of PHP
  319. * currently in use. To implement our own low-level crypto
  320. * in PHP would result in much worse performance and
  321. * consequently in lower iteration counts and hashes that are
  322. * quicker to crack (by non-PHP code).
  323. */
  324. if (PHP_VERSION >= 5) {
  325. $hash = md5($salt . $password, true);
  326. do {
  327. $hash = md5($hash . $password, true);
  328. } while (--$count);
  329. } else {
  330. $hash = pack('H*', md5($salt . $password));
  331. do {
  332. $hash = pack('H*', md5($hash . $password));
  333. } while (--$count);
  334. }
  335. $output = substr($setting, 0, 12);
  336. $output .= _phpbb_hash_encode64($hash, 16, $itoa64);
  337. return $output;
  338. }
  339. /**
  340. * Encode hash
  341. * * @copyright (c) 2005 phpBB Group
  342. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  343. */
  344. function _phpbb_hash_encode64($input, $count, &$itoa64)
  345. {
  346. $output = '';
  347. $i = 0;
  348. do
  349. {
  350. $value = ord($input[$i++]);
  351. $output .= $itoa64[$value & 0x3f];
  352. if ($i < $count)
  353. {
  354. $value |= ord($input[$i]) << 8;
  355. }
  356. $output .= $itoa64[($value >> 6) & 0x3f];
  357. if ($i++ >= $count)
  358. {
  359. break;
  360. }
  361. if ($i < $count)
  362. {
  363. $value |= ord($input[$i]) << 16;
  364. }
  365. $output .= $itoa64[($value >> 12) & 0x3f];
  366. if ($i++ >= $count)
  367. {
  368. break;
  369. }
  370. $output .= $itoa64[($value >> 18) & 0x3f];
  371. }
  372. while ($i < $count);
  373. return $output;
  374. }