From d7621c2c01074bdcabd6a8c1a8e95c95d00319bf Mon Sep 17 00:00:00 2001 From: Florian Pritz Date: Fri, 29 Aug 2014 17:41:33 +0200 Subject: add multipaste support Signed-off-by: Florian Pritz --- application/models/mfile.php | 118 +++++++++++++++++++-------- application/models/mmultipaste.php | 160 +++++++++++++++++++++++++++++++++++++ 2 files changed, 246 insertions(+), 32 deletions(-) create mode 100644 application/models/mmultipaste.php (limited to 'application/models') diff --git a/application/models/mfile.php b/application/models/mfile.php index c900b297c..427c74a18 100644 --- a/application/models/mfile.php +++ b/application/models/mfile.php @@ -71,15 +71,14 @@ class Mfile extends CI_Model { function get_filedata($id) { $sql = ' - SELECT hash, filename, mimetype, date, user, filesize + SELECT id, hash, filename, mimetype, date, user, filesize FROM `files` WHERE `id` = ? LIMIT 1'; $query = $this->db->query($sql, array($id)); - if ($query->num_rows() == 1) { - $return = $query->result_array(); - return $return[0]; + if ($query->num_rows() > 0) { + return $query->row_array(); } else { return false; } @@ -214,10 +213,15 @@ class Mfile extends CI_Model { $mimetype = $this->mimetype($this->file($hash)); $filesize = filesize($this->file($hash)); - $query = $this->db->query(' - INSERT INTO `files` (`hash`, `id`, `filename`, `user`, `date`, `mimetype`, `filesize`) - VALUES (?, ?, ?, ?, ?, ?, ?)', - array($hash, $id, $filename, $userid, time(), $mimetype, $filesize)); + $this->db->insert("files", array( + "id" => $id, + "hash" => $hash, + "filename" => $filename, + "date" => time(), + "user" => $userid, + "mimetype" => $mimetype, + "filesize" => $filesize, + )); } function adopt($id) @@ -241,9 +245,7 @@ class Mfile extends CI_Model { $file = $this->file($filedata['hash']); if (!file_exists($file)) { - if (isset($filedata["hash"])) { - $this->db->query('DELETE FROM files WHERE hash = ?', array($filedata['hash'])); - } + $this->delete_hash($filedata["hash"]); return false; } @@ -262,10 +264,9 @@ class Mfile extends CI_Model { // if the file has been uploaded multiple times the mtime is the time // of the last upload if (filemtime($file) < $remove_before) { - unlink($file); - $this->db->query('DELETE FROM files WHERE hash = ?', array($filedata['hash'])); + $this->delete_hash($filedata["hash"]); } else { - $this->db->query('DELETE FROM files WHERE id = ? LIMIT 1', array($id)); + $this->delete_id($id); } return false; } @@ -273,13 +274,28 @@ class Mfile extends CI_Model { return true; } - function get_timeout_string($id) + public function get_timeout($id) { $filedata = $this->get_filedata($id); $file = $this->file($filedata["hash"]); + if ($this->config->item("upload_max_age") == 0) { + return -1; + } + if (filesize($file) > $this->config->item("small_upload_size")) { - return date("r", $filedata["date"] + $this->config->item("upload_max_age")); + return $filedata["date"] + $this->config->item("upload_max_age"); + } else { + return -1; + } + } + + public function get_timeout_string($id) + { + $timeout = $this->get_timeout($id); + + if ($timeout >= 0) { + return date("r", $timeout); } else { return "unknown"; } @@ -301,34 +317,72 @@ class Mfile extends CI_Model { } } - function delete_id($id) + public function delete_id($id) { $filedata = $this->get_filedata($id); - $userid = $this->muser->get_userid(); - if (!$this->id_exists($id)) { - return false; - } - - $sql = ' - DELETE - FROM `files` - WHERE `id` = ? - AND user = ? - LIMIT 1'; - $this->db->query($sql, array($id, $userid)); + // Delete the file and all multipastes using it + // Note that this does not delete all relations in multipaste_file_map + // which is actually done by a SQL contraint. + // TODO: make it work properly without the constraint + $this->db->query(' + DELETE m, mfm, f + FROM files f + LEFT JOIN multipaste_file_map mfm ON f.id = mfm.file_url_id + LEFT JOIN multipaste m ON mfm.multipaste_id = m.multipaste_id + WHERE f.id = ? + ', array($id)); if ($this->id_exists($id)) { return false; } - if ($this->unused_file($filedata['hash'])) { - unlink($this->file($filedata['hash'])); - @rmdir($this->folder($filedata['hash'])); + if ($filedata !== false) { + assert(isset($filedata["hash"])); + if ($this->unused_file($filedata['hash'])) { + unlink($this->file($filedata['hash'])); + $dir = $this->folder($filedata['hash']); + if (count(scandir($dir)) == 2) { + rmdir($dir); + } + } } return true; } + public function delete_hash($hash) + { + // Delete all files with this hash and all multipastes using any of those files + // Note that this does not delete all relations in multipaste_file_map + // which is actually done by a SQL contraint. + // TODO: make it work properly without the constraint + $this->db->query(' + DELETE m, mfm, f + FROM files f + LEFT JOIN multipaste_file_map mfm ON f.id = mfm.file_url_id + LEFT JOIN multipaste m ON mfm.multipaste_id = m.multipaste_id + WHERE f.hash = ? + ', array($hash)); + + if (file_exists($this->file($hash))) { + unlink($this->file($hash)); + $dir = $this->folder($hash); + if (count(scandir($dir)) == 2) { + rmdir($dir); + } + } + return true; + } + + public function get_owner($id) + { + return $this->db->query(" + SELECT user + FROM files + WHERE id = ? + ", array($id))->row_array()["user"]; + } + public function get_lexers() { return cache_function('lexers', 1800, function() { $lexers = array(); diff --git a/application/models/mmultipaste.php b/application/models/mmultipaste.php new file mode 100644 index 000000000..723132a50 --- /dev/null +++ b/application/models/mmultipaste.php @@ -0,0 +1,160 @@ + + * + * Licensed under AGPLv3 + * (see COPYING for full license text) + * + */ + +class Mmultipaste extends CI_Model { + + function __construct() + { + parent::__construct(); + $this->load->model("muser"); + $this->load->model("mfile"); + } + + /** + * Returns an unused ID + * + * @param min minimal length of the resulting ID + * @param max maximum length of the resulting ID + */ + public function new_id($min = 3, $max = 6) + { + static $id_blacklist = NULL; + + if ($id_blacklist == NULL) { + // This prevents people from being unable to access their uploads + // because of URL rewriting + $id_blacklist = scandir(FCPATH); + $id_blacklist[] = "file"; + $id_blacklist[] = "user"; + } + + $max_tries = 100; + + for ($try = 0; $try < $max_tries; $try++) { + $id = "m-".random_alphanum($min, $max); + + // TODO: try to insert the id into file_groups instead of checking with + // id_exists (prevents race conditio) + if ($this->id_exists($id) || in_array($id, $id_blacklist)) { + continue; + } + + $this->db->insert("multipaste", array( + "url_id" => $id, + "user_id" => $this->muser->get_userid(), + "date" => time(), + )); + + return $id; + } + + show_error("Failed to find unused ID after $max_tries tries."); + } + + public function id_exists($id) + { + if (!$id) { + return false; + } + + $sql = ' + SELECT multipaste.url_id + FROM multipaste + WHERE multipaste.url_id = ? + LIMIT 1'; + $query = $this->db->query($sql, array($id)); + + if ($query->num_rows() == 1) { + return true; + } else { + return false; + } + } + + public function valid_id($id) + { + $files = $this->get_files($id); + foreach ($files as $file) { + if (!$this->mfile->valid_id($file["id"])) { + return false; + } + } + return true; + } + + public function delete_id($id) + { + $this->db->query(' + DELETE m, mfm + FROM multipaste m + LEFT JOIN multipaste_file_map mfm ON mfm.multipaste_id = m.multipaste_id + WHERE m.url_id = ? + ', array($id)); + + if ($this->id_exists($id)) { + return false; + } + + return true; + } + + public function get_owner($id) + { + return $this->db->query(" + SELECT user_id + FROM multipaste + WHERE url_id = ? + ", array($id))->row_array()["user_id"]; + } + + public function get_multipaste($id) + { + return $this->db->query(" + SELECT url_id, user_id, date + FROM multipaste + WHERE url_id = ? + ", array($id))->row_array(); + } + + public function get_files($url_id) + { + $ret = array(); + + $query = $this->db->query(" + SELECT mfm.file_url_id + FROM multipaste_file_map mfm + JOIN multipaste m ON m.multipaste_id = mfm.multipaste_id + WHERE m.url_id = ? + ORDER BY mfm.sort_order + ", array($url_id))->result_array(); + + foreach ($query as $row) { + $filedata = $this->mfile->get_filedata($row["file_url_id"]); + $ret[] = $filedata; + } + + return $ret; + } + + public function get_multipaste_id($url_id) + { + $query = $this->db->query(" + SELECT multipaste_id + FROM multipaste + WHERE url_id = ? + ", array($url_id)); + + if ($query->num_rows() > 0) { + return $query->row_array()["multipaste_id"]; + } + + return false; + } + +} -- cgit v1.2.3-24-g4f1b