what is the simplest way to upload a file in mySql db in play 2.0 ?
Uploading files in the database or in a upload folder and then save a link in the database?
I would go for saving the reference in the database and uploading the image somewhere on your webserver. Or, if you persist on saving the image in the DB, save it as a thumb, this wil keep you database size maintainable and your db size acceptable. DBs are in my opinion for data and not assets like images.
Uploading files is documented: http://www.playframework.org/documentation/2.0/JavaFileUpload
How I did it:
View
In the view, make sure you have the correct enctype (this one is based on the twitter bootstrap)
#helper.form(controllers.orders.routes.Task.save, 'class -> "form-horizontal", 'enctype -> "multipart/form-data")
The file input:
#inputFile(taskForm("file1"), '_display -> "Attachment", '_label -> Messages("file"))
In your controller
// first i get the id of the task where I want to attach my files to
MultipartFormData body = request().body().asMultipartFormData();
List<FilePart> resourceFiles = body.getFiles();
Then iterate trough the attachments and upload them to the upload folder:
for (int i = 0; i < resourceFiles.size(); i++) {
FilePart picture = body.getFile(resourceFiles.get(i).getKey());
String fileName = picture.getFilename();
File file = picture.getFile();
File destinationFile = new File(play.Play.application().path().toString() + "//public//uploads//"
+ newTask.getCode() + "//" + i + "_" + fileName);
System.out.println(play.Play.application().path());
System.out.println(file.getAbsolutePath());
try {
FileUtils.copyFile(file, destinationFile);
TaskDocument taskDocument = new TaskDocument(newTask.description, "/assets/uploads/"
+ newTask.getCode() + "/" + i + "_" + fileName, loggedInUsr, newTask);
taskDocument.save();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Result
The code above result in creating a folder and placing the files in that folder. Example:
Folder: T000345
0_orange.png
1_apple.png
2_pear.png
EDIT : 2012-06-23
If you receive the error about the commons package you have to include this in the file Build.scala:
val appDependencies = Seq(
// Add your project dependencies here,
"mysql" % "mysql-connector-java" % "5.1.18",
"org.specs2" %% "specs2" % "1.9" % "test",
"commons-io" % "commons-io" % "2.2") // at least this one must be present!
Another way, you can store reference to photo in database.
In view:
<form action="#routes.Application.index" method="POST" enctype="multipart/form-data">
Photo<input type="file" name="photo"> <br>
<input type="submit" value="Submit">
</form>
In controller:
MultipartFormData body = request().body().asMultipartFormData();
FilePart photo = body.getFile("photo");
if (photo != null) {
String fileName = photo.getFilename();
File file = photo.getFile();
File newFile = new File(play.Play.application().path().toString() + "//public//uploads//"+ "_" + fileName);
file.renameTo(newFile); //here you are moving photo to new directory
System.out.println(newFile.getPath()); //this path you can store in database
}
}
Related
I'm using the following when trying to open a local file:
some document
When I click the above in a browser, it opens Finder to the folder. But does not open the file. Should I be doing something else to have the file open in Numbers?
You cannot open local files on the client. This would be a huge security risk.
You can link to files on your server (like you did) or you can ask the client for a file using <input type="file">
You can only open some types of files in browsers, like html css js and mp4, otherwise the browser will want to download it. Also remember that browsers replace spaces with %20. I recommend right clicking the file and opening it with chrome then copy that link and using it.
You can open files that are local as long as it is a file that is on the file that is trying to open another file is local.
Your issue is likely the space in the document name. Try this instead:
some document
The %20 will be read by your browser as a space.
Update
The other answer points out something I missed. The .numbers extension will not be able to be opened directly by your browser. Additionally the other answer describes the security risk this could create.
The File API in HTML 5 now allows you to work with local files directly from JS (after basic user interaction in selecting the file(s), for security).
From the Mozilla File API docs:
"The File interface provides information about files and allows JavaScript in a web page to access their content.
File objects are generally retrieved from a FileList object returned as a result of a user selecting files using the <input> element, from a drag and drop operation's DataTransfer object, or from the mozGetAsFile() API on an HTMLCanvasElement."
For more info and code examples, see the sample demo linked from the same article.
This might not be what you're trying to do, but someone out there may find it helpful:
If you want to share a link (by email for example) to a network file you can do so like this:
file:///Volumes/SomeNetworkFolder/Path/To/file.html
This however also requires that the recipient connects to the network folder in finder --- in menu bar,
Go > Connect to Server
enter server address (e.g. file.yourdomain.com - "SomeNetworkFolder" will be inside this directory) and click Connect. Now the link above should work.
Here is the alternative way to download local file by client side and server side effort:
<a onclick='fileClick(this)' href="file://C:/path/to/file/file.html"/>
js:
function fileClick(a) {
var linkTag = a.href;
var substring = "file:///";
if (linkTag.includes(substring)) {
var url = '/v/downloadLocalfile?path=' +
encodeURIComponent(linkTag);
fileOpen(url);
}
else {
window.open(linkTag, '_blank');
}
}
function fileOpen(url) {
$.ajax({
url: url,
complete: function (jqxhr, txt_status) {
console.log("Complete: [ " + txt_status + " ] " + jqxhr);
if (txt_status == 'success') {
window.open(url, '_self');
}
else {
alert("File not found[404]!");
}
// }
}
});
}
Server side[java]:
#GetMapping("/v/downloadLocalfile")
public void downloadLocalfile(#RequestParam String path, HttpServletResponse
response) throws IOException, JRException {
try {
String nPath = path.replace("file:///", "").trim();
File file = new File(nPath);
String fileName = file.getName();
response.setHeader("Content-Disposition", "attachment;filename=" +
fileName);
if (file.exists()) {
FileInputStream in = new FileInputStream(file);
response.setStatus(200);
OutputStream out = response.getOutputStream();
byte[] buffer = new byte[1024];
int numBytesRead;
while ((numBytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, numBytesRead);
}
// out.flush();
in.close();
out.close();
}
else {
response.setStatus(404);
}
} catch (Exception ex) {
logger.error(ex.getLocalizedMessage());
}
return;
}
You can expose your entire file system in your browser by using an http server.
caddy2 server
caddy file-server --listen :2022 --browse --root /
serves the root file system at http://localhost:2022/
python3 built-in server
python3 -m http.server
serves current dir on http://localhost:8000/
python2 built-in server
python3 -m SimpleHTTPServer
serves current dir on http://localhost:8000/
This s
I want to know how to add a local file path as a link and after adding it i want to download the file while clicking the link in asp.net.
My code:
<a href="D:/Sample/test.html" runat="server">
Here i just add my local path to the server.But here nothing done while clicking the link. I want to use .zip file instead of .html file.Let me know how to upload and download by using a link.Thanks in advance
I fail to see the problem here. Just add "~/" to find file from the root of your project and add runat="server" to the anchor link:
Download Zip File
You need to resolve it from the root because while you may know that it's on the D drive on your local machine, you cannot be sure that will be the same on the server. And even if it is on the same drive on the server, what if someone migrates it later on?
As for uploading a file, simply use the Upload control?
There are lots of situation, Using this code you can do it.
File Upload Code
string FilePath = "";
string[] a = new string[1];
string fileName = "";
string FullName = "";
if (FileUploader.FileName.Length > 0)
{
a = FileUploader.FileName.Split('.');
fileName = Convert.ToString(System.DateTime.Now.Ticks) + "." + a.GetValue(1).ToString();
FilePath = Server.MapPath(#"~\SavedFolder");
Fup1.SaveAs(FilePath + #"\" + fileName);
FullName = FilePath + #"\" + fileName;
// Database Saved Code
}
File Download Code
string filename = "filename from Database";
Response.ContentType = "application/octet-stream";
Response.AppendHeader("Content-Disposition", "attachment;filename=" + filename);
string aaa = Server.MapPath("~/SavedFolder/" + filename);
Response.TransmitFile(Server.MapPath("~/SavedFolder/" + filename));
Response.End();
try {
Path temp = Files.createTempFile(filename + "-", "." + extension);
file = temp.toFile();
//file = File.createTempFile(filename + "-", "." + extension, tempfolder);
try (InputStream input = event.getFile().getInputstream()) {
Files.copy(input, temp, StandardCopyOption.REPLACE_EXISTING);
}
FileInputStream inputStream = new FileInputStream(file);
try {
DbxEntry.File uploadedFile = client.uploadFile("/"+filename,
DbxWriteMode.add(), file.length(), inputStream);
System.out.println("Uploaded: " + uploadedFile.toString());
String fileurl = client.createShareableUrl("/"+filename);
System.out.println(fileurl);
//insertFileLink(fileurl);
} finally {
inputStream.close();
}
file.deleteOnExit();
} catch (IOException e) {
e.printStackTrace(); //log this
status="Failure";
message = event.getFile().getFileName() + "is not uploaded.Try again.";
}
I can get links like below with the help of the code piece above:
https://www.dropbox.com/s/asqjcgnu5fjn2a8/photo?dl=0
Basically my goal is, when someone upload a photo to my website, I will store the actual file in Dropbox, and the link of the file in my database.
I will give this link to my html files and it will be shown in the website user interface. For example someone's profile picture.
The links that I want should be like this: http://i.imgur.com/TRr3u73.jpg
Hope I am clear.
Is there a way to get such links using Dropbox API?
You're almost there with your existing code. Try adding the query parameter raw=1 to the URL, but also make sure the file name has a good extension. (You won't be able to view the example image you gave in the browser, since Dropbox doesn't know it's an image.)
See https://www.dropbox.com/help/201 for details about viewing share links.
I have previously successfully managed to upload a file using the webimage helper, but i am now trying to combine that with creating a directory, and failing miserably. here is my code:
if(IsPost){
//Create Directory using PropertyID
var imageroot = Server.MapPath("~/Images/Property/");
var foldername = rPropertyId.ToString();
var path = Path.Combine(imageroot, foldername);
if(!Directory.Exists(path)){
Directory.CreateDirectory(path);
}
photo = WebImage.GetImageFromRequest();
if(photo != null){
MediumFileName = rPropertyId + "_" + gooid + "_" + "Medium";
imagePath = path + MediumFileName;
photo.Save(#"~\" + imagePath);}
}
First, i create a directory with the name of the propertyID. This works fine. I then try and upload new photo's into that path, and i get an error saying that "The given path's format is not supported".
Any ideas?
You correctly use Path.Combine() when creating the directory path, you should do the same when making the image path.
imagePath = Path.Combine(path, MediumFileName);
Other than that, the error message suggests that perhaps it is the omission of a file extension that is causing issues? Perhaps use Path.GetFileName(photo.FileName) or similar and use that as the end of your constructed pathname.
I'm attempting to create a PDF file from an HTML file. After looking around a little I've found: wkhtmltopdf to be perfect. I need to call this .exe from the ASP.NET server. I've attempted:
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = HttpContext.Current.Server.MapPath("wkhtmltopdf.exe");
p.StartInfo.Arguments = "TestPDF.htm TestPDF.pdf";
p.Start();
p.WaitForExit();
With no success of any files being created on the server. Can anyone give me a pointer in the right direction? I put the wkhtmltopdf.exe file at the top level directory of the site. Is there anywhere else it should be held?
Edit: If anyone has better solutions to dynamically create pdf files from html, please let me know.
Update:
My answer below, creates the pdf file on the disk. I then streamed that file to the users browser as a download. Consider using something like Hath's answer below to get wkhtml2pdf to output to a stream instead and then send that directly to the user - that will bypass lots of issues with file permissions etc.
My original answer:
Make sure you've specified an output path for the PDF that is writeable by the ASP.NET process of IIS running on your server (usually NETWORK_SERVICE I think).
Mine looks like this (and it works):
/// <summary>
/// Convert Html page at a given URL to a PDF file using open-source tool wkhtml2pdf
/// </summary>
/// <param name="Url"></param>
/// <param name="outputFilename"></param>
/// <returns></returns>
public static bool HtmlToPdf(string Url, string outputFilename)
{
// assemble destination PDF file name
string filename = ConfigurationManager.AppSettings["ExportFilePath"] + "\\" + outputFilename + ".pdf";
// get proj no for header
Project project = new Project(int.Parse(outputFilename));
var p = new System.Diagnostics.Process();
p.StartInfo.FileName = ConfigurationManager.AppSettings["HtmlToPdfExePath"];
string switches = "--print-media-type ";
switches += "--margin-top 4mm --margin-bottom 4mm --margin-right 0mm --margin-left 0mm ";
switches += "--page-size A4 ";
switches += "--no-background ";
switches += "--redirect-delay 100";
p.StartInfo.Arguments = switches + " " + Url + " " + filename;
p.StartInfo.UseShellExecute = false; // needs to be false in order to redirect output
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true; // redirect all 3, as it should be all 3 or none
p.StartInfo.WorkingDirectory = StripFilenameFromFullPath(p.StartInfo.FileName);
p.Start();
// read the output here...
string output = p.StandardOutput.ReadToEnd();
// ...then wait n milliseconds for exit (as after exit, it can't read the output)
p.WaitForExit(60000);
// read the exit code, close process
int returnCode = p.ExitCode;
p.Close();
// if 0 or 2, it worked (not sure about other values, I want a better way to confirm this)
return (returnCode == 0 || returnCode == 2);
}
I had the same problem when i tried using msmq with a windows service but it was very slow for some reason. (the process part).
This is what finally worked:
private void DoDownload()
{
var url = Request.Url.GetLeftPart(UriPartial.Authority) + "/CPCDownload.aspx?IsPDF=False?UserID=" + this.CurrentUser.UserID.ToString();
var file = WKHtmlToPdf(url);
if (file != null)
{
Response.ContentType = "Application/pdf";
Response.BinaryWrite(file);
Response.End();
}
}
public byte[] WKHtmlToPdf(string url)
{
var fileName = " - ";
var wkhtmlDir = "C:\\Program Files\\wkhtmltopdf\\";
var wkhtml = "C:\\Program Files\\wkhtmltopdf\\wkhtmltopdf.exe";
var p = new Process();
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = wkhtml;
p.StartInfo.WorkingDirectory = wkhtmlDir;
string switches = "";
switches += "--print-media-type ";
switches += "--margin-top 10mm --margin-bottom 10mm --margin-right 10mm --margin-left 10mm ";
switches += "--page-size Letter ";
p.StartInfo.Arguments = switches + " " + url + " " + fileName;
p.Start();
//read output
byte[] buffer = new byte[32768];
byte[] file;
using(var ms = new MemoryStream())
{
while(true)
{
int read = p.StandardOutput.BaseStream.Read(buffer, 0,buffer.Length);
if(read <=0)
{
break;
}
ms.Write(buffer, 0, read);
}
file = ms.ToArray();
}
// wait or exit
p.WaitForExit(60000);
// read the exit code, close process
int returnCode = p.ExitCode;
p.Close();
return returnCode == 0 ? file : null;
}
Thanks Graham Ambrose and everyone else.
OK, so this is an old question, but an excellent one. And since I did not find a good answer, I made my own :) Also, I've posted this super simple project to GitHub.
Here is some sample code:
var pdfData = HtmlToXConverter.ConvertToPdf("<h1>SOO COOL!</h1>");
Here are some key points:
No P/Invoke
No creating of a new process
No file-system (all in RAM)
Native .NET DLL with intellisense, etc.
Ability to generate a PDF or PNG (HtmlToXConverter.ConvertToPng)
Check out the C# wrapper library (using P/Invoke) for the wkhtmltopdf library: https://github.com/pruiz/WkHtmlToXSharp
There are many reason why this is generally a bad idea. How are you going to control the executables that get spawned off but end up living on in memory if there is a crash? What about denial-of-service attacks, or if something malicious gets into TestPDF.htm?
My understanding is that the ASP.NET user account will not have the rights to logon locally. It also needs to have the correct file permissions to access the executable and to write to the file system. You need to edit the local security policy and let the ASP.NET user account (maybe ASPNET) logon locally (it may be in the deny list by default). Then you need to edit the permissions on the NTFS filesystem for the other files. If you are in a shared hosting environment it may be impossible to apply the configuration you need.
The best way to use an external executable like this is to queue jobs from the ASP.NET code and have some sort of service monitor the queue. If you do this you will protect yourself from all sorts of bad things happening. The maintenance issues with changing the user account are not worth the effort in my opinion, and whilst setting up a service or scheduled job is a pain, its just a better design. The ASP.NET page should poll a result queue for the output and you can present the user with a wait page. This is acceptable in most cases.
You can tell wkhtmltopdf to send it's output to sout by specifying "-" as the output file.
You can then read the output from the process into the response stream and avoid the permissions issues with writing to the file system.
My take on this with 2018 stuff.
I am using async. I am streaming to and from wkhtmltopdf. I created a new StreamWriter because wkhtmltopdf is expecting utf-8 by default but it is set to something else when the process starts.
I didn't include a lot of arguments since those varies from user to user. You can add what you need using additionalArgs.
I removed p.WaitForExit(...) since I wasn't handling if it fails and it would hang anyway on await tStandardOutput. If timeout is needed, then you would have to call Wait(...) on the different tasks with a cancellationtoken or timeout and handle accordingly.
public async Task<byte[]> GeneratePdf(string html, string additionalArgs)
{
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = #"C:\Program Files\wkhtmltopdf\wkhtmltopdf.exe",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
Arguments = "-q -n " + additionalArgs + " - -";
};
using (var p = Process.Start(psi))
using (var pdfSream = new MemoryStream())
using (var utf8Writer = new StreamWriter(p.StandardInput.BaseStream,
Encoding.UTF8))
{
await utf8Writer.WriteAsync(html);
utf8Writer.Close();
var tStdOut = p.StandardOutput.BaseStream.CopyToAsync(pdfSream);
var tStdError = p.StandardError.ReadToEndAsync();
await tStandardOutput;
string errors = await tStandardError;
if (!string.IsNullOrEmpty(errors)) { /* deal/log with errors */ }
return pdfSream.ToArray();
}
}
Things I haven't included in there but could be useful if you have images, css or other stuff that wkhtmltopdf will have to load when rendering the html page:
you can pass the authentication cookie using --cookie
in the header of the html page, you can set the base tag with href pointing to the server and wkhtmltopdf will use that if need be
Thanks for the question / answer / all the comments above. I came upon this when I was writing my own C# wrapper for WKHTMLtoPDF and it answered a couple of the problems I had. I ended up writing about this in a blog post - which also contains my wrapper (you'll no doubt see the "inspiration" from the entries above seeping into my code...)
Making PDFs from HTML in C# using WKHTMLtoPDF
Thanks again guys!
The ASP .Net process probably doesn't have write access to the directory.
Try telling it to write to %TEMP%, and see if it works.
Also, make your ASP .Net page echo the process's stdout and stderr, and check for error messages.
Generally return code =0 is coming if the pdf file is created properly and correctly.If it's not created then the value is in -ve range.
using System;
using System.Diagnostics;
using System.Web;
public partial class pdftest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
private void fn_test()
{
try
{
string url = HttpContext.Current.Request.Url.AbsoluteUri;
Response.Write(url);
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName =
#"C:\PROGRA~1\WKHTML~1\wkhtmltopdf.exe";//"wkhtmltopdf.exe";
startInfo.Arguments = url + #" C:\test"
+ Guid.NewGuid().ToString() + ".pdf";
Process.Start(startInfo);
}
catch (Exception ex)
{
string xx = ex.Message.ToString();
Response.Write("<br>" + xx);
}
}
protected void btn_test_Click(object sender, EventArgs e)
{
fn_test();
}
}