return $params;
}
+ /**
+ * Search through the server files.
+ *
+ * The query parameter will be used in conjuction with the SQL directive
+ * LIKE, so include '%' in it if you need to. This search will always ignore
+ * user files and directories. Note that the search is case insensitive.
+ *
+ * This query can quickly become inefficient so use it sparignly.
+ *
+ * @param string $query The string used with SQL LIKE.
+ * @param integer $from The offset to start the search at.
+ * @param integer $limit The maximum number of results.
+ * @param boolean $count When true this methods returns the number of results availabe,
+ * disregarding the parameters $from and $limit.
+ * @return int|array Integer when count, otherwise array of stored_file objects.
+ */
+ public function search_server_files($query, $from = 0, $limit = 20, $count = false) {
+ global $DB;
+ $params = array(
+ 'contextlevel' => CONTEXT_USER,
+ 'directory' => '.',
+ 'query' => $query
+ );
+
+ if ($count) {
+ $select = 'COUNT(1)';
+ } else {
+ $select = self::instance_sql_fields('f', 'r');
+ }
+ $like = $DB->sql_like('f.filename', ':query', false);
+
+ $sql = "SELECT $select
+ FROM {files} f
+ LEFT JOIN {files_reference} r
+ ON f.referencefileid = r.id
+ JOIN {context} c
+ ON f.contextid = c.id
+ WHERE c.contextlevel <> :contextlevel
+ AND f.filename <> :directory
+ AND " . $like . "";
+
+ if ($count) {
+ return $DB->count_records_sql($sql, $params);
+ }
+
+ $sql .= " ORDER BY f.filename";
+
+ $result = array();
+ $filerecords = $DB->get_recordset_sql($sql, $params, $from, $limit);
+ foreach ($filerecords as $filerecord) {
+ $result[$filerecord->pathnamehash] = $this->get_file_instance($filerecord);
+ }
+ $filerecords->close();
+
+ return $result;
+ }
+
/**
* Returns all aliases that refer to some stored_file via the given reference
*
global $CFG, $USER, $OUTPUT;
$ret = array();
$ret['dynload'] = true;
- $ret['nosearch'] = true;
+ $ret['nosearch'] = false;
$ret['nologin'] = true;
$ret['list'] = array();
);
}
+ /**
+ * Search through all the files.
+ *
+ * This method will do a raw search through the database, then will try
+ * to match with files that a user can access. A maximum of 50 files will be
+ * returned at a time, excluding possible duplicates found along the way.
+ *
+ * Queries are done in chunk of 100 files to prevent too many records to be fetched
+ * at once. When too many files are not included, or a maximum of 10 queries are
+ * performed we consider that this was the last page.
+ *
+ * @param String $q The query string.
+ * @param integer $page The page number.
+ * @return array of results.
+ */
+ public function search($q, $page = 1) {
+ global $DB, $SESSION;
+
+ // Because the repository API is weird, the first page is 0, but it should be 1.
+ if (!$page) {
+ $page = 1;
+ }
+
+ if (!isset($SESSION->repository_local_search)) {
+ $SESSION->repository_local_search = array();
+ }
+
+ $fs = get_file_storage();
+ $fb = get_file_browser();
+
+ $max = 50;
+ $limit = 100;
+ if ($page <= 1) {
+ $SESSION->repository_local_search['query'] = $q;
+ $SESSION->repository_local_search['from'] = 0;
+ $from = 0;
+ } else {
+ // Yes, the repository does not send the query again...
+ $q = $SESSION->repository_local_search['query'];
+ $from = (int) $SESSION->repository_local_search['from'];
+ }
+
+ $count = $fs->search_server_files('%' . $DB->sql_like_escape($q) . '%', null, null, true);
+ $remaining = $count - $from;
+ $maxloops = 3000;
+ $loops = 0;
+
+ $results = array();
+ while (count($results) < $max && $maxloops > 0 && $remaining > 0) {
+ if (empty($files)) {
+ $files = $fs->search_server_files('%' . $DB->sql_like_escape($q) . '%', $from, $limit);
+ $from += $limit;
+ };
+
+ $remaining--;
+ $maxloops--;
+ $loops++;
+
+ $file = array_shift($files);
+ if (!$file) {
+ // This should not happen.
+ throw new coding_exception('Unexpected end of files list.');
+ }
+
+ $key = $file->get_contenthash() . ':' . $file->get_filename();
+ if (isset($results[$key])) {
+ // We found the file with same content and same name, let's skip it.
+ continue;
+ }
+
+ $ctx = context::instance_by_id($file->get_contextid());
+ $fileinfo = $fb->get_file_info($ctx, $file->get_component(), $file->get_filearea(), $file->get_itemid(),
+ $file->get_filepath(), $file->get_filename());
+ if ($fileinfo) {
+ $results[$key] = $this->get_node($fileinfo);
+ }
+
+ }
+
+ // Save the position for the paging to work.
+ if ($maxloops > 0 && $remaining > 0) {
+ $SESSION->repository_local_search['from'] += $loops;
+ $pages = -1;
+ } else {
+ $SESSION->repository_local_search['from'] = 0;
+ $pages = 0;
+ }
+
+ $return = array(
+ 'list' => array_values($results),
+ 'dynload' => true,
+ 'pages' => $pages,
+ 'page' => $page
+ );
+
+ return $return;
+ }
+
/**
* Is this repository accessing private data?
*