/** * Gets the names of all attachments (if any) * @return array Array of attachment names (may be empty). Names only, * not including path to attachment folder */ public function get_attachment_names() { $result = array(); if (!$this->has_attachments()) { return $result; } $folder = $this->get_attachment_folder(); $handle = forum_utils::opendir($folder); while (false !== ($name = readdir($handle))) { if ($name != '.' && $name != '..') { if (!is_dir("{$folder}/{$name}")) { $result[] = $name; } } } closedir($handle); sort($result); return $result; }
/** * Given a parent folder, deletes all folders within it (and their * contents) if they are older than 24 hours. * @param float $start Start time * @param string $folder Folder path */ private static function clear_old_folders($start, $folder) { // Threshold is 24 hours ago $threshold = time() - 24 * 3600; // Loop through all files in folder $killed = 0; $spared = 0; $handle = forum_utils::opendir($folder); while (($file = readdir($handle)) !== false) { if ($file == '.' || $file == '..') { continue; } // Check it's a folder $target = "{$folder}/{$file}"; if (!is_dir($target)) { continue; } // Check time if (filemtime($target) < $threshold) { // Older than threshold - delete if (!remove_dir($target)) { mtrace("\nError deleting folder: {$target}"); } $killed++; } else { $spared++; } } closedir($handle); mtrace("({$killed} deleted, {$spared} left): " . round(microtime(true) - $start, 1)); }
/** * Lists all files in a playspace. * @param string $playspaceid ID of playspace (two comma-separated numbers) * @param bool $duplicates If true, actually lists duplicate files * @return array Array of full names including paths */ static function get_attachment_playspace_files($playspaceid, $duplicates) { $folder = self::get_attachment_playspace_folder($playspaceid); if ($duplicates) { self::delete_attachment_playspace($playspaceid, true); forum_utils::mkdir("{$folder}/" . self::DUPLICATESFOLDER); } $handle = forum_utils::opendir($folder); $result = array(); while (false !== ($name = readdir($handle))) { if ($name != '.' && $name != '..' && $name != self::DUPLICATESFOLDER) { $path = "{$folder}/{$name}"; if ($duplicates) { $duplicate = "{$folder}/" . self::DUPLICATESFOLDER . "/{$name}"; forum_utils::copy($path, $duplicate); $result[] = $duplicate; } else { $result[] = $path; } } } closedir($handle); return $result; }
/** * Merges the contents of this discussion into another discussion. * @param forum_discussion $targetdiscussion Target discussion * @param int $userid User ID (0 = current) * @param bool $log True to log this action */ public function merge_into($targetdiscussion, $userid = 0, $log = true) { global $CFG; forum_utils::start_transaction(); // Update parent post id of root post $record = new stdClass(); $record->id = $this->discussionfields->postid; $record->parentpostid = $targetdiscussion->discussionfields->postid; forum_utils::update_record('forumng_posts', $record); // Move all posts into new discussion forum_utils::execute_sql("UPDATE {$CFG->prefix}forumng_posts SET " . "discussionid=" . $targetdiscussion->get_id() . " WHERE discussionid=" . $this->get_id()); // Delete this discussion forum_utils::delete_records('forumng_discussions', 'id', $this->discussionfields->id); // Merge attachments (if any) $oldfolder = $this->get_attachment_folder(); $newfolder = $targetdiscussion->get_attachment_folder(); if (is_dir($oldfolder)) { $handle = forum_utils::opendir($oldfolder); $madenewfolder = false; while (false !== ($name = readdir($handle))) { if ($name != '.' && $name != '..') { if (!$madenewfolder) { check_dir_exists($newfolder, true, true); $madenewfolder = true; } $oldname = $oldfolder . '/' . $name; $newname = $newfolder . '/' . $name; forum_utils::rename($oldname, $newname); } } closedir($handle); } // Merging the discussion into another might cause completion changes // (if there was a requirement for discussions and this is no longer // a discussion in its own right). $this->update_completion(false); if ($log) { $this->log('merge discussion d' . $targetdiscussion->get_id()); } forum_utils::finish_transaction(); $this->uncache(); $targetdiscussion->uncache(); }
/** * Edits an existing message. The previous version of the message is * retained for admins to view if needed. * @param string $subject Subject * @param string $message Message * @param int $format Moodle format ID * @param mixed $deleteattachments Array of names (only) of existing * attachments to delete, or 'true' to delete all * @param array $newattachments Additional attachments to add (if any) * @param bool $setimportant If true, highlight the post * @param bool $mailnow New value of mailnow flag (ignored if message was already mailed) * @param int $userid Userid doing the editing (0 = current) */ function edit($subject, $message, $format, $deleteattachments = array(), $newattachments = array(), $setimportant = false, $mailnow = false, $userid = 0, $log = true) { $now = time(); // Create copy of existing entry ('old version') $copy = clone $this->postfields; $copy->subject = is_null($copy->subject) ? null : addslashes($copy->subject); $copy->message = addslashes($copy->message); // Copy has oldversion set to 1 and parentpost set to id of real post $copy->oldversion = 1; $copy->parentpostid = $copy->id; unset($copy->id); // OK, add copy forum_utils::start_transaction(); $copyid = forum_utils::insert_record('forumng_posts', $copy); // If there are attachments... $attachments = $this->get_attachment_names(); $copiedattachments = 0; if ($attachments) { // NOTE: The names are confusing. $newfolder is the EXISTING folder // but it relates to the attachments for the NEW version of the // post. $oldfolder is a newly-created folder but it relates to // attachments for the OLD version of the posdt $newfolder = $this->get_attachment_folder(); $oldfolder = $this->get_attachment_folder($copyid); // Copy the attachments folder to an 'old' historic one, then // delete files from the current attachment folder. This used to be // done with rename but we experienced failures when creating the // folder with the same name as the one we just renamed away. forum_utils::mkdir($oldfolder); $handle = forum_utils::opendir($newfolder); $keepfolder = false; while (false !== ($name = readdir($handle))) { if ($name != '.' && $name != '..') { $source = "{$newfolder}/{$name}"; // Copy file to the 'old' version folder forum_utils::copy($source, "{$oldfolder}/{$name}"); // Consider whether it should be deleted from the 'new' // version folder if ($deleteattachments === true || $deleteattachments && in_array($name, $deleteattachments)) { forum_utils::unlink($source); } else { $keepfolder = true; $copiedattachments++; } } } closedir($handle); if (!$keepfolder) { forum_utils::rmdir($newfolder); } } // Update existing entry with new data where it changed $update = new StdClass(); $gotsubject = false; if ($subject !== $this->postfields->subject) { $update->subject = strlen(trim($subject)) == 0 ? null : addslashes($subject); $gotsubject = true; } if ($message !== $this->postfields->message) { $update->message = addslashes($message); } if ($format != $this->postfields->format) { $update->format = $format; } if ($copiedattachments == 0 && count($newattachments) == 0 && $this->postfields->attachments) { $update->attachments = 0; } else { if (count($newattachments) > 0 && !$this->postfields->attachments) { $update->attachments = 1; } } if ($setimportant) { $update->important = 1; } else { $update->important = 0; } if ($this->postfields->mailstate == forum::MAILSTATE_NOT_MAILED && $mailnow) { $update->mailstate = forum::MAILSTATE_NOW_NOT_MAILED; } else { if ($this->postfields->mailstate == forum::MAILSTATE_NOW_NOT_MAILED && !$mailnow) { $update->mailstate = forum::MAILSTATE_NOT_MAILED; } } $update->modified = $now; $update->edituserid = forum_utils::get_real_userid($userid); if (count((array) $update) > 0) { $update->id = $this->postfields->id; forum_utils::update_record('forumng_posts', $update); } // Add new attachments foreach ($newattachments as $path) { $this->add_attachment($path); } if ($log) { $this->log('edit post'); } // Update in-memory representation foreach ((array) $update as $name => $value) { $this->postfields->{$name} = $value === null ? null : stripslashes($value); } // If this is the root post, then changing its subject affects // the discussion subhject if ($this->is_root_post() && $gotsubject) { $this->discussion->hack_subject($this->postfields->subject); } // Uncache before updating search (want to make sure that the recursive // update gets latest data) $this->get_discussion()->uncache(); // Update search index if (isset($update->message) || $gotsubject) { // Update for this post $this->search_update(); // If changing the subject of a root post, update all posts in the // discussion (ugh) if ($this->is_root_post() && $gotsubject) { $this->search_update_children(); } } forum_utils::finish_transaction(); }