diff --git a/lib/filelib.php b/lib/filelib.php index faf4ae6978c..e2f19c94fe0 100644 --- a/lib/filelib.php +++ b/lib/filelib.php @@ -2070,6 +2070,70 @@ function send_temp_file_finished($path) { } } +/** + * Serve content which is not meant to be cached. + * + * This is only intended to be used for volatile public files, for instance + * when development is enabled, or when caching is not required on a public resource. + * + * @param string $content Raw content. + * @param string $filename The file name. + * @return void + */ +function send_content_uncached($content, $filename) { + $mimetype = mimeinfo('type', $filename); + $charset = strpos($mimetype, 'text/') === 0 ? '; charset=utf-8' : ''; + + header('Content-Disposition: inline; filename="' . $filename . '"'); + header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 2) . ' GMT'); + header('Pragma: '); + header('Accept-Ranges: none'); + header('Content-Type: ' . $mimetype . $charset); + header('Content-Length: ' . strlen($content)); + + echo $content; + die(); +} + +/** + * Safely save content to a certain path. + * + * This function tries hard to be atomic by first copying the content + * to a separate file, and then moving the file across. It also prevents + * the user to abort a request to prevent half-safed files. + * + * This function is intended to be used when saving some content to cache like + * $CFG->localcachedir. If you're not caching a file you should use the File API. + * + * @param string $content The file content. + * @param string $destination The absolute path of the final file. + * @return void + */ +function file_safe_save_content($content, $destination) { + global $CFG; + + clearstatcache(); + if (!file_exists(dirname($destination))) { + @mkdir(dirname($destination), $CFG->directorypermissions, true); + } + + // Prevent serving of incomplete file from concurrent request, + // the rename() should be more atomic than fwrite(). + ignore_user_abort(true); + if ($fp = fopen($destination . '.tmp', 'xb')) { + fwrite($fp, $content); + fclose($fp); + rename($destination . '.tmp', $destination); + @chmod($destination, $CFG->filepermissions); + @unlink($destination . '.tmp'); // Just in case anything fails. + } + ignore_user_abort(false); + if (connection_aborted()) { + die(); + } +} + /** * Handles the sending of file data to the user's browser, including support for * byteranges etc.