telemetry_db.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. <?php
  2. require_once 'idObfuscation.php';
  3. define('TELEMETRY_SETTINGS_FILE', 'telemetry_settings.php');
  4. /**
  5. * @return PDO|false
  6. */
  7. function getPdo($returnErrorMessage = false)
  8. {
  9. if (
  10. !file_exists(TELEMETRY_SETTINGS_FILE)
  11. || !is_readable(TELEMETRY_SETTINGS_FILE)
  12. ) {
  13. if($returnErrorMessage){
  14. return 'missing TELEMETRY_SETTINGS_FILE';
  15. }
  16. return false;
  17. }
  18. require TELEMETRY_SETTINGS_FILE;
  19. if (!isset($db_type)) {
  20. if($returnErrorMessage){
  21. return "db_type not set in '" . TELEMETRY_SETTINGS_FILE . "'";
  22. }
  23. return false;
  24. }
  25. $pdoOptions = [
  26. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
  27. ];
  28. try {
  29. if ('mssql' === $db_type) {
  30. if (!isset(
  31. $MsSql_server,
  32. $MsSql_databasename,
  33. $MsSql_WindowsAuthentication
  34. )) {
  35. if($returnErrorMessage){
  36. return "Required MSSQL database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
  37. }
  38. return false;
  39. }
  40. if (!$MsSql_WindowsAuthentication and
  41. !isset(
  42. $MsSql_username,
  43. $MsSql_password
  44. )
  45. ) {
  46. if($returnErrorMessage){
  47. return "Required MSSQL database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
  48. }
  49. return false;
  50. }
  51. $dsn = 'sqlsrv:'
  52. .'server='.$MsSql_server
  53. .';Database='.$MsSql_databasename;
  54. if($MsSql_TrustServerCertificate === true){
  55. $dsn = $dsn . ';TrustServerCertificate=1';
  56. }
  57. if($MsSql_TrustServerCertificate === false){
  58. $dsn = $dsn . ';TrustServerCertificate=0';
  59. }
  60. if($MsSql_WindowsAuthentication){
  61. return new PDO($dsn, "", "", $pdoOptions);
  62. } else {
  63. return new PDO($dsn, $MsSql_username, $MsSql_password, $pdoOptions);
  64. }
  65. }
  66. if ('mysql' === $db_type) {
  67. if (!isset(
  68. $MySql_hostname,
  69. $MySql_port,
  70. $MySql_databasename,
  71. $MySql_username,
  72. $MySql_password
  73. )) {
  74. if($returnErrorMessage){
  75. return "Required mysql database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
  76. }
  77. return false;
  78. }
  79. $dsn = 'mysql:'
  80. .'host='.$MySql_hostname
  81. .';port='.$MySql_port
  82. .';dbname='.$MySql_databasename;
  83. return new PDO($dsn, $MySql_username, $MySql_password, $pdoOptions);
  84. }
  85. if ('sqlite' === $db_type) {
  86. if (!isset($Sqlite_db_file)) {
  87. if($returnErrorMessage){
  88. return "Required sqlite database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
  89. }
  90. return false;
  91. }
  92. // Check if directory exists and is writable
  93. $db_dir = dirname($Sqlite_db_file);
  94. if (!is_dir($db_dir)) {
  95. if ($returnErrorMessage) {
  96. return "SQLite database directory does not exist: " . $db_dir . ". Please create it and ensure it's writable by the web server.";
  97. }
  98. return false;
  99. }
  100. if (!is_writable($db_dir)) {
  101. if ($returnErrorMessage) {
  102. return "SQLite database directory is not writable: " . $db_dir . ". Please ensure the web server has write permissions (e.g., chmod 755 or 775).";
  103. }
  104. return false;
  105. }
  106. $pdo = new PDO('sqlite:'.$Sqlite_db_file, null, null, $pdoOptions);
  107. # TODO: Why create table only in sqlite mode?
  108. $pdo->exec('
  109. CREATE TABLE IF NOT EXISTS `speedtest_users` (
  110. `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
  111. `ispinfo` text,
  112. `extra` text,
  113. `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  114. `ip` text NOT NULL,
  115. `ua` text NOT NULL,
  116. `lang` text NOT NULL,
  117. `dl` text,
  118. `ul` text,
  119. `ping` text,
  120. `jitter` text,
  121. `log` longtext
  122. );
  123. ');
  124. return $pdo;
  125. }
  126. if ('postgresql' === $db_type) {
  127. if (!isset(
  128. $PostgreSql_hostname,
  129. $PostgreSql_databasename,
  130. $PostgreSql_username,
  131. $PostgreSql_password
  132. )) {
  133. if($returnErrorMessage){
  134. return "Required postgresql database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
  135. }
  136. return false;
  137. }
  138. $dsn = 'pgsql:'
  139. .'host='.$PostgreSql_hostname
  140. .';dbname='.$PostgreSql_databasename;
  141. return new PDO($dsn, $PostgreSql_username, $PostgreSql_password, $pdoOptions);
  142. }
  143. } catch (Exception $e) {
  144. if($returnErrorMessage){
  145. return $e->getMessage();
  146. }
  147. return false;
  148. }
  149. if($returnErrorMessage){
  150. return "db_type '" . $db_type . "' not supported";
  151. }
  152. return false;
  153. }
  154. /**
  155. * @return bool
  156. */
  157. function isObfuscationEnabled()
  158. {
  159. require TELEMETRY_SETTINGS_FILE;
  160. return
  161. isset($enable_id_obfuscation)
  162. && true === $enable_id_obfuscation;
  163. }
  164. /**
  165. * @return string|false returns the id of the inserted column or false on error if returnErrorMessage is false or a error message if returnErrorMessage is true
  166. */
  167. function insertSpeedtestUser($ip, $ispinfo, $extra, $ua, $lang, $dl, $ul, $ping, $jitter, $log, $returnExceptionOnError = false)
  168. {
  169. $pdo = getPdo();
  170. if (!($pdo instanceof PDO)) {
  171. if($returnExceptionOnError){
  172. return new Exception("Failed to get database connection object");
  173. }
  174. return false;
  175. }
  176. try {
  177. $stmt = $pdo->prepare(
  178. 'INSERT INTO speedtest_users
  179. (ip,ispinfo,extra,ua,lang,dl,ul,ping,jitter,log)
  180. VALUES (?,?,?,?,?,?,?,?,?,?)'
  181. );
  182. $stmt->execute([
  183. $ip, $ispinfo, $extra, $ua, $lang, $dl, $ul, $ping, $jitter, $log
  184. ]);
  185. $id = $pdo->lastInsertId();
  186. } catch (Exception $e) {
  187. if($returnExceptionOnError){
  188. return $e;
  189. }
  190. return false;
  191. }
  192. if (isObfuscationEnabled()) {
  193. return obfuscateId($id);
  194. }
  195. return $id;
  196. }
  197. /**
  198. * @param int|string $id
  199. *
  200. * @return array|null|false|exception returns the speedtest data as array, null
  201. * if no data is found for the given id or
  202. * false or an exception if there was an error (based on returnExceptionOnError)
  203. *
  204. * @throws RuntimeException
  205. */
  206. function getSpeedtestUserById($id,$returnExceptionOnError = false)
  207. {
  208. $pdo = getPdo();
  209. if (!($pdo instanceof PDO)) {
  210. if($returnExceptionOnError){
  211. return new Exception("Failed to get database connection object");
  212. }
  213. return false;
  214. }
  215. if (isObfuscationEnabled()) {
  216. $id = deobfuscateId($id);
  217. }
  218. try {
  219. $stmt = $pdo->prepare(
  220. 'SELECT
  221. id, timestamp, ip, ispinfo, ua, lang, dl, ul, ping, jitter, log, extra
  222. FROM speedtest_users
  223. WHERE id = :id'
  224. );
  225. $stmt->bindValue(':id', $id, PDO::PARAM_INT);
  226. $stmt->execute();
  227. $row = $stmt->fetch(PDO::FETCH_ASSOC);
  228. } catch (Exception $e) {
  229. if($returnExceptionOnError){
  230. return $e;
  231. }
  232. return false;
  233. }
  234. if (!is_array($row)) {
  235. return null;
  236. }
  237. $row['id_formatted'] = $row['id'];
  238. if (isObfuscationEnabled()) {
  239. $row['id_formatted'] = obfuscateId($row['id']).' (deobfuscated: '.$row['id'].')';
  240. }
  241. return $row;
  242. }
  243. /**
  244. * @return array|false
  245. */
  246. function getLatestSpeedtestUsers()
  247. {
  248. $pdo = getPdo();
  249. if (!($pdo instanceof PDO)) {
  250. return false;
  251. }
  252. require TELEMETRY_SETTINGS_FILE;
  253. try {
  254. $sql = 'SELECT ';
  255. if('mssql' === $db_type) {$sql .= ' TOP(100) ';}
  256. $sql .= ' id, timestamp, ip, ispinfo, ua, lang, dl, ul, ping, jitter, log, extra
  257. FROM speedtest_users
  258. ORDER BY timestamp DESC ';
  259. if('mssql' !== $db_type) {$sql .= ' LIMIT 100 ';}
  260. $stmt = $pdo->query($sql);
  261. $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  262. foreach ($rows as $i => $row) {
  263. $rows[$i]['id_formatted'] = $row['id'];
  264. if (isObfuscationEnabled()) {
  265. $rows[$i]['id_formatted'] = obfuscateId($row['id']).' (deobfuscated: '.$row['id'].')';
  266. }
  267. }
  268. } catch (Exception $e) {
  269. return false;
  270. }
  271. return $rows;
  272. }