PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/usr/share/owncloud/apps/mozilla_sync/lib/storage.php

https://gitlab.com/thiagotalma/stalag13
PHP | 501 lines | 281 code | 84 blank | 136 comment | 59 complexity | 57c7bac065d1ac14dc151570325f146a MD5 | raw file
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Michal Jaskurzynski
  6. * @author Oliver Gasser
  7. * @copyright 2012 Michal Jaskurzynski mjaskurzynski@gmail.com
  8. *
  9. */
  10. namespace OCA\mozilla_sync;
  11. class Storage
  12. {
  13. /**
  14. * @brief Get index of collection, if collection doesn't exist it will be
  15. * created.
  16. *
  17. * @param string $syncId The Sync user that the collection is belonging to.
  18. * @param string $collectionName The name of the collection.
  19. */
  20. static public function collectionNameToIndex($syncId, $collectionName) {
  21. $query = \OCP\DB::prepare('SELECT `id` FROM
  22. `*PREFIX*mozilla_sync_collections` WHERE `userid` = ? AND
  23. `name` = ?');
  24. $result = $query->execute(array($syncId, $collectionName));
  25. // Collection found, return its ID
  26. $row = $result->fetchRow();
  27. if ($row) {
  28. return $row['id'];
  29. }
  30. // No collection found, create new collection
  31. $query = \OCP\DB::prepare('INSERT INTO
  32. `*PREFIX*mozilla_sync_collections` (`userid`, `name`) VALUES
  33. (?, ?)');
  34. $result = $query->execute(array($syncId, $collectionName));
  35. // Creation of collection failed
  36. if ($result === false) {
  37. Utils::writeLogDbError("DB: Could not create collection " . $collectionName . ".", $query);
  38. return false;
  39. }
  40. return \OCP\DB::insertid('*PREFIX*mozilla_sync_collections');
  41. }
  42. /**
  43. * @brief Delete old WBO.
  44. *
  45. * @return bool True when old WBO were deleted, false otherwise.
  46. */
  47. static public function deleteOldWbo() {
  48. $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*mozilla_sync_wbo` WHERE
  49. `ttl` > 0 AND (`modified` + `ttl`) < CAST(? AS DECIMAL(12,2))');
  50. $result = $query->execute(array(Utils::getMozillaTimestamp()));
  51. if ($result === false) {
  52. // Also returns false when no old WBO was found -> don't Utils::writeLog() as it would spam the log
  53. return false;
  54. }
  55. return true;
  56. }
  57. /**
  58. * @brief Store new Weave Basic Object or update previous one.
  59. *
  60. * @param string $syncId The Sync user whose WBO is updated.
  61. * @param int $collectionId The collection ID whose WBO is updated.
  62. * @param float $modifiedTime The modification time that will be saved for
  63. * the updated WBO.
  64. * @param array $wboArray WBO which will be updated. Passed as JSON array.
  65. * @return boolean True on success, false otherwise.
  66. */
  67. static public function saveWBO($syncId, $modifiedTime, $collectionId, $wboArray) {
  68. if (!array_key_exists('id', $wboArray)) {
  69. Utils::writeLog("Failed to save WBO as no ID was present.");
  70. return false;
  71. }
  72. $query = \OCP\DB::prepare('SELECT 1 FROM `*PREFIX*mozilla_sync_wbo`
  73. WHERE `collectionid` = ? AND `name` = ?');
  74. $result = $query->execute(array($collectionId, $wboArray['id']));
  75. // No WBO found, add a new one
  76. if ($result->fetchRow() === false) {
  77. return self::insertWBO($syncId, $modifiedTime, $collectionId, $wboArray);
  78. } else {
  79. return self::updateWBO($syncId, $modifiedTime, $collectionId, $wboArray);
  80. }
  81. }
  82. /**
  83. * @brief Delete a WBO.
  84. *
  85. * @param integer $syncId The Sync user whose WBO will be deleted.
  86. * @param integer $collectionId Collection ID whose WBO will be deleted.
  87. * @param integer $wboId WBO's ID which will be deleted.
  88. * @return boolean True on success, false otherwise.
  89. */
  90. static public function deleteWBO($syncId, $collectionId, $wboId) {
  91. $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*mozilla_sync_wbo`
  92. WHERE `collectionid` = ? AND `name` = ?');
  93. $result = $query->execute(array($collectionId, $wboId));
  94. if ($result === false) {
  95. Utils::writeLogDbError("DB: Could not delete WBO " . $wboId . ".", $query, \OCP\Util::INFO);
  96. return false;
  97. }
  98. return true;
  99. }
  100. /**
  101. * @brief Inserts a new WBO into the database.
  102. *
  103. * @param integer $syncId The Sync user whose WBO will be inserted.
  104. * @param integer $collectionId Collection ID whose WBO will be inserted.
  105. * @param integer $wboId WBO's ID which will be inserted.
  106. * @param array $wboArray WBO as JSON array which will be inserted into the
  107. * database.
  108. * @return True on success, false otherwise.
  109. */
  110. static private function insertWBO($syncId, $modifiedTime, $collectionId, $wboArray) {
  111. $queryString = 'INSERT INTO `*PREFIX*mozilla_sync_wbo` (`collectionid`, `name`, `modified`, `payload`';
  112. $queryArgs = array($collectionId, $wboArray['id'], $modifiedTime, $wboArray['payload']);
  113. $valuesString = 'VALUES (?,?,?,?';
  114. // Add values from array to insert query statement
  115. $wboArgs = array('`sortindex`', '`ttl`', '`parentid`', '`predecessorid`');
  116. foreach ($wboArgs as $value) {
  117. if (array_key_exists($value, $wboArray)) {
  118. $queryString .= ', ' .$value;
  119. $queryArgs[] = $wboArray[$value];
  120. $valuesString .= ',?';
  121. }
  122. }
  123. $valuesString .= ')';
  124. $queryString .= ') ' .$valuesString;
  125. $query = \OCP\DB::prepare($queryString);
  126. $result = $query->execute($queryArgs);
  127. if ($result === false) {
  128. Utils::writeLogDbError("DB: Could not insert WBO for user " . $syncId . " in collection " . $collectionId . ".", $query);
  129. return false;
  130. }
  131. return true;
  132. }
  133. /**
  134. * @brief Updates an already existing WBO.
  135. *
  136. * @param integer $syncId The Sync user whose WBO will be updated.
  137. * @param number $modifiedTime Updated last modification time.
  138. * @param integer $collectionId Collection ID whose WBO will be updated.
  139. * @param array $wboArray WBO as JSON array which will be updated in the
  140. * database.
  141. * @return True on success, false otherwise.
  142. */
  143. static private function updateWBO($syncId, $modifiedTime, $collectionId, $wboArray) {
  144. $queryString= 'UPDATE `*PREFIX*mozilla_sync_wbo` SET `modified` = ?';
  145. $queryArgs = array($modifiedTime);
  146. // Add values from array to update query statement
  147. $wboArgs = array('sortindex', 'ttl', 'parentid', 'predecessorid', 'payload');
  148. foreach ($wboArgs as $value) {
  149. if (array_key_exists($value, $wboArray)) {
  150. $queryString .= ', ' .$value. '=?';
  151. $queryArgs[] = $wboArray[$value];
  152. }
  153. }
  154. $queryString .= ' WHERE `collectionid` = ? AND `name` = ?';
  155. array_push($queryArgs, $collectionId, $wboArray['id']);
  156. $query = \OCP\DB::prepare($queryString);
  157. $result = $query->execute($queryArgs);
  158. if ($result === false) {
  159. Utils::writeLogDbError("DB: Could not update WBO for user " . $syncId . " in collection " . $collectionId . ".", $query);
  160. return false;
  161. }
  162. return true;
  163. }
  164. /**
  165. * @brief Delete complete storage for a user.
  166. *
  167. * @param integer $syncId The user's Sync ID whose storage will be deleted.
  168. * @return boolean True on success, false otherwise.
  169. */
  170. static public function deleteStorage($syncId) {
  171. // Delete all WBO for this user
  172. $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*mozilla_sync_wbo` WHERE
  173. `collectionid` IN (SELECT `id` FROM `*PREFIX*mozilla_sync_collections`
  174. WHERE `userid` = ?)');
  175. $result = $query->execute(array($syncId));
  176. if ($result === false) {
  177. Utils::writeLogDbError("DB: Could not delete storage for user " . $syncId . ".", $query);
  178. return false;
  179. }
  180. // Delete all collections for this user
  181. $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*mozilla_sync_collections`
  182. WHERE `userid` = ?');
  183. $result = $query->execute(array($syncId));
  184. if ($result === false) {
  185. Utils::writeLogDbError("DB: Could not delete collections for user " . $syncId . ".", $query);
  186. return false;
  187. }
  188. return true;
  189. }
  190. /**
  191. * @brief Convert modifiers array to SQL string, query arguments, limit and
  192. * offset.
  193. *
  194. * @param array &$modifiers Array containing the modifiers for the SQL
  195. * statement.
  196. * @param array &$queryArgs Array with the query arguments.
  197. * @param int &$limit The number of elements which will be retrieved.
  198. * @param int &$offset Elements starting from this offset will be retrieved.
  199. * @return string Returns the WHERE SQL string.
  200. */
  201. static public function modifiersToString(&$modifiers, &$queryArgs, &$limit, &$offset) {
  202. $whereString = '';
  203. // IDs
  204. if (isset($modifiers['ids'])) {
  205. if (gettype($modifiers['ids']) === 'array') {
  206. $first = true;
  207. $whereString .= ' AND (';
  208. foreach ($modifiers['ids'] as $value) {
  209. if ($first) {
  210. $first = false;
  211. } else {
  212. $whereString .= ' OR ';
  213. }
  214. $whereString .= '`name` = ?';
  215. $queryArgs[] = $value;
  216. }
  217. $whereString .= ')';
  218. } else {
  219. $whereString .= ' AND `name` = ?';
  220. $queryArgs[] = $modifiers['ids'];
  221. }
  222. }
  223. // Predecessor ID
  224. if (isset($modifiers['predecessorid'])) {
  225. $whereString .= ' AND `predecessorid` = ?';
  226. $queryArgs[] = $modifiers['predecessorid'];
  227. }
  228. // Parent ID
  229. if (isset($modifiers['parentid'])) {
  230. $whereString .= ' AND `parentid` = ?';
  231. $queryArgs[] = $modifiers['parentid'];
  232. }
  233. // Time modifiers
  234. if (isset($modifiers['older'])) {
  235. $whereString .= ' AND `modified` <= CAST( ? AS DECIMAL(12,2))';
  236. $queryArgs[] = $modifiers['older'];
  237. } else if (isset($modifiers['newer'])) {
  238. $whereString .= ' AND `modified` >= CAST( ? AS DECIMAL(12,2))';
  239. $queryArgs[] = $modifiers['newer'];
  240. } else if (isset($modifiers['index_above'])) {
  241. $whereString .= ' AND `sortindex` >= ?';
  242. $queryArgs[] = $modifiers['index_above'];
  243. } else if (isset($modifiers['index_below'])) {
  244. $whereString .= ' AND `sortindex` <= ?';
  245. $queryArgs[] = $modifiers['index_below'];
  246. }
  247. // Sort
  248. if (isset($modifiers['sort'])) {
  249. if ($modifiers['sort'] === 'oldest') {
  250. $whereString .= ' ORDER BY `modified` ASC';
  251. } else if ($modifiers['sort'] === 'newest') {
  252. $whereString .= ' ORDER BY `modified` DESC';
  253. } else if ($modifiers['sort'] === 'index') {
  254. $whereString .= ' ORDER BY `sortindex` DESC';
  255. }
  256. }
  257. // Limit
  258. if (isset($modifiers['limit'])) {
  259. $limit = intval($modifiers['limit']);
  260. }
  261. // Offset
  262. if (isset($modifiers['offset'])) {
  263. $offset = intval($modifiers['offset']);
  264. }
  265. return $whereString;
  266. }
  267. /**
  268. * @brief Gets the time of the last modification for the logged in user.
  269. *
  270. * @return string Last modification time.
  271. */
  272. public static function getLastModifiedTime() {
  273. // Get collections with all modification times
  274. $modifieds = self::getCollectionModifiedTimes();
  275. if ($modifieds === false) {
  276. return false;
  277. }
  278. // Iterate through collections to find last modified record
  279. $lastMod = false;
  280. foreach ($modifieds as $modified) {
  281. $curr = intval($modified);
  282. if ($lastMod === false || $curr > $lastMod) {
  283. $lastMod = $curr;
  284. }
  285. }
  286. $formatStr = "Y-m-d H:i:s T";
  287. return date($formatStr, $lastMod);
  288. }
  289. /**
  290. * @brief Get the last modification times for all collections of a user.
  291. *
  292. * @param string $syncId The Sync user ID whose collections are queried, currently logged in user by default.
  293. * @return mixed Array of collection => modified.
  294. */
  295. public static function getCollectionModifiedTimes($syncId = NULL) {
  296. // Get logged in user by default
  297. if (is_null($syncId)) {
  298. $syncId = User::userNameToSyncId(\OCP\User::getUser());
  299. }
  300. if ($syncId === false) {
  301. Utils::writeLog("Failed to get user ID before getting the collection modified times.");
  302. return false;
  303. }
  304. $query = \OCP\DB::prepare('SELECT `name`, (SELECT max(`modified`) FROM
  305. `*PREFIX*mozilla_sync_wbo` WHERE
  306. `*PREFIX*mozilla_sync_wbo`.`collectionid` =
  307. `*PREFIX*mozilla_sync_collections`.`id`) AS `modified` FROM
  308. `*PREFIX*mozilla_sync_collections` WHERE `userid` = ?');
  309. $result = $query->execute(array($syncId));
  310. if ($result === false) {
  311. Utils::writeLogDbError("DB: Could not get info collections for user " .
  312. $syncId . ".", $query);
  313. return false;
  314. }
  315. $resultArray = array();
  316. while (($row = $result->fetchRow())) {
  317. // Skip empty collections
  318. if (is_null($row['modified'])) {
  319. continue;
  320. }
  321. // Cast returned values to the correct type
  322. $row = StorageService::forceTypeCasting($row);
  323. $key = $row['name'];
  324. $value = $row['modified'];
  325. $resultArray[$key] = $value;
  326. }
  327. return $resultArray;
  328. }
  329. /**
  330. * @brief Get the total size of stored data for the logged in user.
  331. *
  332. * @return int Size of stored data in kB.
  333. */
  334. public static function getSyncSize() {
  335. // Get all collections with their sizes
  336. $sizes = self::getCollectionSizes();
  337. if ($sizes === false) {
  338. return false;
  339. }
  340. // Iterate through collections and add sizes
  341. $totalSize = 0;
  342. foreach ($sizes as $size) {
  343. $totalSize = $totalSize + ((int) $size);
  344. }
  345. return $totalSize;
  346. }
  347. /**
  348. * @brief Get the size of each collection for a user.
  349. *
  350. * Returns the size of each collection for a specific user in kB. For SQLite
  351. * the number of thousand characters are returned, since there is no byte length
  352. * function for SQLite databases.
  353. *
  354. * @param string $syncId The Sync user whose collection sizes are returned,
  355. * the logged in user by default.
  356. * @return mixed Array of collection => size in kB for the specified user.
  357. */
  358. public static function getCollectionSizes($syncId = NULL) {
  359. // Get logged in user by default
  360. if (is_null($syncId)) {
  361. $syncId = User::userNameToSyncId(\OCP\User::getUser());
  362. }
  363. if ($syncId === false) {
  364. Utils::writeLog("Failed to get user ID before getting the collection sizes.");
  365. return false;
  366. }
  367. $query = \OCP\DB::prepare('SELECT name, (SELECT SUM(LENGTH(payload))
  368. FROM *PREFIX*mozilla_sync_wbo WHERE
  369. *PREFIX*mozilla_sync_wbo.collectionid =
  370. *PREFIX*mozilla_sync_collections.id) as size FROM
  371. *PREFIX*mozilla_sync_collections WHERE userid = ?');
  372. $result = $query->execute(array($syncId));
  373. if ($result === false) {
  374. Utils::writeLogDbError("DB: Could not get info collection usage for user "
  375. . $syncId . ".", $query);
  376. return false;
  377. }
  378. $resultArray = array();
  379. while (($row = $result->fetchRow())) {
  380. // Skip empty collections
  381. if (is_null($row['size'])) {
  382. continue;
  383. }
  384. $key = $row['name'];
  385. // Convert bytes to kB
  386. $value = ((float) $row['size'])/1024.0;
  387. $resultArray[$key] = $value;
  388. }
  389. return $resultArray;
  390. }
  391. /**
  392. * @brief Gets the number of sync clients for a user.
  393. *
  394. * @param string $syncId The Sync user whose number of clients are returned, the logged in user by default.
  395. * @return int The number of clients associated with the specified user.
  396. */
  397. public static function getNumClients($syncId = NULL) {
  398. // Get logged in user by default
  399. if (is_null($syncId)) {
  400. $syncId = User::userNameToSyncId(\OCP\User::getUser());
  401. }
  402. if ($syncId === false) {
  403. Utils::writeLog("Failed to get user ID before getting the number of clients.");
  404. return false;
  405. }
  406. $query = \OCP\DB::prepare('SELECT COUNT(*) AS `count` FROM `*PREFIX*mozilla_sync_wbo` WHERE `collectionid` = (SELECT `id` FROM `*PREFIX*mozilla_sync_collections` WHERE `name` = ? AND `userid` = ?)');
  407. $result = $query->execute(array('clients', $syncId));
  408. if ($result === false) {
  409. Utils::writeLogDbError("DB: Could not get number of clients for user " .
  410. $syncId . ".", $query);
  411. return false;
  412. }
  413. $row = $result->fetchRow();
  414. return ((int) $row['count']);
  415. }
  416. }
  417. /* vim: set ts=4 sw=4 tw=80 noet : */