/** * Bulk load properties for directory children * * @param Directory $node * @param array $requestedProperties requested properties * * @return void */ private function loadChildrenProperties(Directory $node, $requestedProperties) { $path = $node->getPath(); if (isset($this->cache[$path])) { // we already loaded them at some point return; } $childNodes = $node->getChildren(); // pre-fill cache foreach ($childNodes as $childNode) { $this->cache[$childNode->getPath()] = []; } $sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` LIKE ?'; $sql .= ' AND `propertyname` in (?) ORDER BY `propertypath`, `propertyname`'; $result = $this->connection->executeQuery($sql, array($this->user, $this->connection->escapeLikeParameter(rtrim($path, '/')) . '/%', $requestedProperties), array(null, null, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY)); $oldPath = null; $props = []; while ($row = $result->fetch()) { $path = $row['propertypath']; if ($oldPath !== $path) { // save previously gathered props $this->cache[$oldPath] = $props; $oldPath = $path; // prepare props for next path $props = []; } $props[$row['propertyname']] = $row['propertyvalue']; } if (!is_null($oldPath)) { // save props from last run $this->cache[$oldPath] = $props; } $result->closeCursor(); }
/** * Move a file or folder in the cache * * @param \OC\Files\Cache\Cache $sourceCache * @param string $sourcePath * @param string $targetPath * @throws \OC\DatabaseException */ public function moveFromCache(Cache $sourceCache, $sourcePath, $targetPath) { // normalize source and target $sourcePath = $this->normalize($sourcePath); $targetPath = $this->normalize($targetPath); $sourceData = $sourceCache->get($sourcePath); $sourceId = $sourceData['fileid']; $newParentId = $this->getParentId($targetPath); list($sourceStorageId, $sourcePath) = $sourceCache->getMoveInfo($sourcePath); list($targetStorageId, $targetPath) = $this->getMoveInfo($targetPath); // sql for final update $moveSql = 'UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?'; if ($sourceData['mimetype'] === 'httpd/unix-directory') { //find all child entries $sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?'; $result = $this->connection->executeQuery($sql, [$sourceStorageId, $this->connection->escapeLikeParameter($sourcePath) . '/%']); $childEntries = $result->fetchAll(); $sourceLength = strlen($sourcePath); $this->connection->beginTransaction(); $query = $this->connection->prepare('UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ? WHERE `fileid` = ?'); foreach ($childEntries as $child) { $newTargetPath = $targetPath . substr($child['path'], $sourceLength); $query->execute([$targetStorageId, $newTargetPath, md5($newTargetPath), $child['fileid']]); } $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]); $this->connection->commit(); } else { $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]); } }
/** * get the number of all users matching the search string in a group * @param string $gid * @param string $search * @return int|false * @throws \OC\DatabaseException */ public function countUsersInGroup($gid, $search = '') { $parameters = [$gid]; $searchLike = ''; if ($search !== '') { $parameters[] = '%' . $this->dbConn->escapeLikeParameter($search) . '%'; $searchLike = ' AND `uid` LIKE ?'; } $stmt = \OC_DB::prepare('SELECT COUNT(`uid`) AS `count` FROM `*PREFIX*group_user` WHERE `gid` = ?' . $searchLike); $result = $stmt->execute($parameters); $count = $result->fetchOne(); if ($count !== false) { $count = intval($count); } return $count; }
/** * Searches mapped names by the giving string in the name column * @param string $search * @param string $prefixMatch * @param string $postfixMatch * @return string[] */ public function getNamesBySearch($search, $prefixMatch = "", $postfixMatch = "") { $query = $this->dbc->prepare(' SELECT `owncloud_name` FROM `' . $this->getTableName() . '` WHERE `owncloud_name` LIKE ? '); $res = $query->execute(array($prefixMatch . $this->dbc->escapeLikeParameter($search) . $postfixMatch)); $names = array(); if ($res !== false) { while ($row = $query->fetch()) { $names[] = $row['owncloud_name']; } } return $names; }
/** * search contact * * @param int $addressBookId * @param string $pattern which should match within the $searchProperties * @param array $searchProperties defines the properties within the query pattern should match * @return array an array of contacts which are arrays of key-value-pairs */ public function search($addressBookId, $pattern, $searchProperties) { $query = $this->db->getQueryBuilder(); $query2 = $this->db->getQueryBuilder(); $query2->selectDistinct('cp.cardid')->from($this->dbCardsPropertiesTable, 'cp'); foreach ($searchProperties as $property) { $query2->orWhere($query2->expr()->andX($query2->expr()->eq('cp.name', $query->createNamedParameter($property)), $query2->expr()->like('cp.value', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%')))); } $query2->andWhere($query2->expr()->eq('cp.addressbookid', $query->createNamedParameter($addressBookId))); $query->select('c.carddata')->from($this->dbCardsTable, 'c')->where($query->expr()->in('c.id', $query->createFunction($query2->getSQL()))); $result = $query->execute(); $cards = $result->fetchAll(); $result->closeCursor(); return array_map(function ($array) { return $this->readBlob($array['carddata']); }, $cards); }
/** * {@inheritdoc} */ public function getAllTags($visibilityFilter = null, $nameSearchPattern = null) { $tags = []; $query = $this->connection->getQueryBuilder(); $query->select('*')->from(self::TAG_TABLE); if (!is_null($visibilityFilter)) { $query->andWhere($query->expr()->eq('visibility', $query->createNamedParameter((int) $visibilityFilter))); } if (!empty($nameSearchPattern)) { $query->andWhere($query->expr()->like('name', $query->expr()->literal('%' . $this->connection->escapeLikeParameter($nameSearchPattern) . '%'))); } $query->addOrderBy('name', 'ASC')->addOrderBy('visibility', 'ASC')->addOrderBy('editable', 'ASC'); $result = $query->execute(); while ($row = $result->fetch()) { $tags[$row['id']] = $this->createSystemTagFromRow($row); } $result->closeCursor(); return $tags; }
/** * For a given filter the extension can specify the sql query conditions including parameters for that query. * In case the extension does not know the filter false is to be returned. * The query condition and the parameters are to be returned as array with two elements. * E.g. return array('`app` = ? and `message` like ?', array('mail', 'ownCloud%')); * * @param string $filter * @return array|false */ public function getQueryForFilter($filter) { $user = $this->activityManager->getCurrentUserId(); // Display actions from all files if ($filter === self::FILTER_FILES) { return ['`app` = ?', [self::APP_FILES]]; } if (!$user) { // Remaining filters only work with a user/token return false; } // Display actions from favorites only if ($filter === self::FILTER_FAVORITES || in_array($filter, ['all', 'by', 'self']) && $this->userSettingFavoritesOnly($user)) { try { $favorites = $this->helper->getFavoriteFilePaths($user); } catch (\RuntimeException $e) { // Too many favorites, can not put them into one query anymore... return ['`app` = ?', [self::APP_FILES]]; } /* * Display activities only, when they are not `type` create/change * or `file` is a favorite or in a favorite folder */ $parameters = $fileQueryList = []; $parameters[] = self::APP_FILES; $parameters[] = self::APP_FILES; $fileQueryList[] = '(`type` <> ? AND `type` <> ?)'; $parameters[] = self::TYPE_SHARE_CREATED; $parameters[] = self::TYPE_SHARE_CHANGED; foreach ($favorites['items'] as $favorite) { $fileQueryList[] = '`file` = ?'; $parameters[] = $favorite; } foreach ($favorites['folders'] as $favorite) { $fileQueryList[] = '`file` LIKE ?'; $parameters[] = $this->connection->escapeLikeParameter($favorite) . '/%'; } return [' CASE ' . 'WHEN `app` <> ? THEN 1 ' . 'WHEN `app` = ? AND (' . implode(' OR ', $fileQueryList) . ') THEN 1 ' . 'ELSE 0 ' . 'END = 1 ', $parameters]; } return false; }
/** * Espace a parameter to be used in a LIKE query * * @param string $param * @return string */ public function escapeLikeParameter($param) { return $this->connection->escapeLikeParameter($param); }
/** * Converts legacy home storage ids in the format * "local::/data/dir/path/userid/" to the new format "home::userid" */ public function run(IOutput $out) { // only run once if ($this->config->getAppValue('core', 'repairlegacystoragesdone') === 'yes') { return; } $dataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/'); $dataDir = rtrim($dataDir, '/') . '/'; $dataDirId = 'local::' . $dataDir; $count = 0; $hasWarnings = false; $this->connection->beginTransaction(); // note: not doing a direct UPDATE with the REPLACE function // because regexp search/extract is needed and it is not guaranteed // to work on all database types $sql = 'SELECT `id`, `numeric_id` FROM `*PREFIX*storages`' . ' WHERE `id` LIKE ?' . ' ORDER BY `id`'; $result = $this->connection->executeQuery($sql, array($this->connection->escapeLikeParameter($dataDirId) . '%')); while ($row = $result->fetch()) { $currentId = $row['id']; // one entry is the datadir itself if ($currentId === $dataDirId) { continue; } try { if ($this->fixLegacyStorage($currentId, (int) $row['numeric_id'])) { $count++; } } catch (RepairException $e) { $hasWarnings = true; $out->warning('Could not repair legacy storage ' . $currentId . ' automatically.'); } } // check for md5 ids, not in the format "prefix::" $sql = 'SELECT COUNT(*) AS "c" FROM `*PREFIX*storages`' . ' WHERE `id` NOT LIKE \'%::%\''; $result = $this->connection->executeQuery($sql); $row = $result->fetch(); // find at least one to make sure it's worth // querying the user list if ((int) $row['c'] > 0) { $userManager = \OC::$server->getUserManager(); // use chunks to avoid caching too many users in memory $limit = 30; $offset = 0; do { // query the next page of users $results = $userManager->search('', $limit, $offset); $storageIds = array(); foreach ($results as $uid => $userObject) { $storageId = $dataDirId . $uid . '/'; if (strlen($storageId) <= 64) { // skip short storage ids as they were handled in the previous section continue; } $storageIds[$uid] = $storageId; } if (count($storageIds) > 0) { // update the storages of these users foreach ($storageIds as $uid => $storageId) { $numericId = Storage::getNumericStorageId($storageId); try { if (!is_null($numericId) && $this->fixLegacyStorage($storageId, (int) $numericId)) { $count++; } } catch (RepairException $e) { $hasWarnings = true; $out->warning('Could not repair legacy storage ' . $storageId . ' automatically.'); } } } $offset += $limit; } while (count($results) >= $limit); } $out->info('Updated ' . $count . ' legacy home storage ids'); $this->connection->commit(); if ($hasWarnings) { $out->warning('Some legacy storages could not be repaired. Please manually fix them then re-run ./occ maintenance:repair'); } else { // if all were done, no need to redo the repair during next upgrade $this->config->setAppValue('core', 'repairlegacystoragesdone', 'yes'); } }