* * Licensed under AGPLv3 * (see COPYING for full license text) * */ class File extends MY_Controller { protected $json_enabled_functions = array( "upload_history", "do_upload", "do_delete", "do_multipaste", ); function __construct() { parent::__construct(); $this->load->model('mfile'); $this->load->model('mmultipaste'); if (is_cli_client()) { $this->var->view_dir = "file_plaintext"; } else { $this->var->view_dir = "file"; } } function index() { if ($this->input->is_cli_request()) { $this->load->library("../controllers/tools"); return $this->tools->index(); } // Try to guess what the user would like to do. $id = $this->uri->segment(1); if (!empty($_FILES)) { $this->do_upload(); } elseif (strpos($id, "m-") === 0 && $this->mmultipaste->id_exists($id)) { $this->_download(); } elseif ($id != "file" && $this->mfile->id_exists($id)) { $this->_download(); } elseif ($id && $id != "file") { $this->_non_existent(); } else { $this->upload_form(); } } function _download() { $id = $this->uri->segment(1); $lexer = urldecode($this->uri->segment(2)); $is_multipaste = false; if ($this->mmultipaste->id_exists($id)) { $is_multipaste = true; if(!$this->mmultipaste->valid_id($id)) { return $this->_non_existent(); } $files = $this->mmultipaste->get_files($id); $this->data["title"] = "Multipaste"; } elseif ($this->mfile->id_exists($id)) { if (!$this->mfile->valid_id($id)) { return $this->_non_existent(); } $files = array($this->mfile->get_filedata($id)); $this->data["title"] = htmlspecialchars($files[0]["filename"]); } else { assert(0); } assert($files !== false); assert(is_array($files)); assert(count($files) >= 1); // don't allow unowned files to be downloaded foreach ($files as $filedata) { if ($filedata["user"] == 0) { return $this->_non_existent(); } } $etag = ""; foreach ($files as $filedata) { $etag = sha1($etag.$filedata["hash"]); } // handle some common "lexers" here switch ($lexer) { case "": break; case "qr": handle_etag($etag); header("Content-disposition: inline; filename=\"".$id."_qr.png\"\n"); header("Content-Type: image/png\n"); passthru('qrencode -s 10 -o - '.escapeshellarg(site_url($id).'/')); exit(); case "info": return $this->_display_info($id); default: if ($is_multipaste) { show_error("Invalid action \"".htmlspecialchars($lexer)."\""); } break; } $this->load->driver("ddownload"); // user wants the plain file if ($lexer == 'plain') { assert(count($files) == 1); handle_etag($etag); $filedata = $files[0]; $filepath = $this->mfile->file($filedata["hash"]); $this->ddownload->serveFile($filepath, $filedata["filename"], "text/plain"); exit(); } $this->load->library("output_cache"); foreach ($files as $key => $filedata) { $file = $this->mfile->file($filedata['hash']); // autodetect the lexer for highlighting if the URL contains a / after the ID (/ID/) // /ID/lexer disables autodetection $autodetect_lexer = !$lexer && substr_count(ltrim($this->uri->uri_string(), "/"), '/') >= 1; $autodetect_lexer = $is_multipaste ? true : $autodetect_lexer; if ($autodetect_lexer) { $lexer = $this->mfile->autodetect_lexer($filedata["mimetype"], $filedata["filename"]); } // resolve aliases // this is mainly used for compatibility $lexer = $this->mfile->resolve_lexer_alias($lexer); // if there is no mimetype mapping we can't highlight it $can_highlight = $this->mfile->can_highlight($filedata["mimetype"]); $filesize_too_big = filesize($file) > $this->config->item('upload_max_text_size'); if (!$can_highlight || $filesize_too_big || !$lexer) { if (!$is_multipaste) { // prevent javascript from being executed and forbid frames // this should allow us to serve user submitted HTML content without huge security risks foreach (array("X-WebKit-CSP", "X-Content-Security-Policy", "Content-Security-Policy") as $header_name) { header("$header_name: default-src 'none'; img-src *; media-src *; font-src *; style-src 'unsafe-inline' *; script-src 'none'; object-src *; frame-src 'none'; "); } handle_etag($etag); $this->ddownload->serveFile($file, $filedata["filename"], $filedata["mimetype"]); exit(); } else { switch ($filedata["mimetype"]) { // TODO: handle video/audio // TODO: handle more image formats (thumbnails needs to be improved) case "image/jpeg": case "image/png": case "image/gif": $filedata["tooltip"] = $this->_tooltip_for_image($filedata); $filedata["orientation"] = libraries\Image::get_exif_orientation($file); $this->output_cache->add_merge( array("items" => array($filedata)), 'file/fragments/thumbnail' ); break; default: $this->output_cache->add_merge( array("items" => array($filedata)), 'file/fragments/uploads_table' ); break; } continue; } } $this->output_cache->add_function(function() use ($filedata, $lexer, $is_multipaste) { $this->_highlight_file($filedata, $lexer, $is_multipaste); }); } // TODO: move lexers json to dedicated URL $this->data['lexers'] = $this->mfile->get_lexers(); // Output everything // Don't use the output class/append_output because it does too // much magic ({elapsed_time} and {memory_usage}). // Direct echo puts us on the safe side. echo $this->load->view($this->var->view_dir.'/html_header', $this->data, true); $this->output_cache->render(); echo $this->load->view($this->var->view_dir.'/html_footer', $this->data, true); } private function _colorify($file, $lexer, $anchor_id = false) { $return_value = 0; $output = ""; $lines_to_remove = 0; $output .= '
'."\n";
ob_start();
if ($lexer == "ascii") {
passthru('ansi2html -p < '.escapeshellarg($file), $return_value);
// Last line is empty
$lines_to_remove = 1;
} else {
passthru('pygmentize -F codetagify -O encoding=guess,outencoding=utf8,stripnl=False -l '.escapeshellarg($lexer).' -f html '.escapeshellarg($file), $return_value);
// Last 2 items are "
", "", $line);
}
$anchor = "n$line_number";
if ($anchor_id !== false) {
$anchor = "n-$anchor_id-$line_number";
}
// Be careful not to add superflous whitespace here (we are in a )
$output .= ""
.""
." "
.""
."".$line."\n";
$output .= "";
}
$output .= "
$message
"), "file/fragments/alert-wide" ); } } $data = array_merge($this->data, array( 'title' => htmlspecialchars($filedata['filename']), 'id' => $filedata["id"], 'current_highlight' => htmlspecialchars($lexer), 'timeout' => $this->mfile->get_timeout_string($filedata["id"]), 'filedata' => $filedata, )); $this->output_cache->render_now($data, $this->var->view_dir.'/html_paste_header'); $this->output_cache->render_now($highlit["output"]); $this->output_cache->render_now($data, $this->var->view_dir.'/html_paste_footer'); } private function _tooltip_for_image($filedata) { $filesize = format_bytes($filedata["filesize"]); list($width, $height) = getimagesize($this->mfile->file($filedata["hash"])); $upload_date = date("r", $filedata["date"]); $tooltip = "${filedata["id"]} - $filesizeContact info not available.
'; } $this->load->view('header', $this->data); $this->load->view('contact', $this->data); $this->load->view('footer', $this->data); } /* Functions below this comment can only be run via the CLI * `php index.php file