I am looking for the best way to upload the XML file to the GAE DataStore from the web page. The XML will be later parsed and modified wia the web interface. So far I am using the HTMLform with file typeinput:
<form enctype="multipart/form-data" action="update" method="post" >
<input type="file" name="myfile" />
<input type="submit" />
</form>
In the servlet class I use the for loop to read the data into String:
InputStream input = req.getInputStream();
StringBuffer sb = new StringBuffer("");
int c = -1;
while ( (c = input.read() ) != -1 )
{
char ch = (char) c;
sb.append( ch );
}
Then I check if the DataStore contains the entity with application hardcoded key value and if not I create a new entity and upload the XML into Text (com.google.appengine.api.datastore.Text), otherwise I create a new entity and put the file there. Is that something you can call the good approach?
Regards,
STeN
If you use a html form with type="file" field, then browser will upload the file via http POST with a multipart/form-data content type.
See AppEngine docs on how to handle properly multipart content data.
Related
I need to upload image and video files to the server in an Angular application using Laravel 5.1 as the back end. All Ajax requests need to go to the Laravel controller first, and we have the code there for how the file gets handled when it gets there. We have previously done normal HTML forms to submit file uploads to the controller, but in this case we need to avoid the page refresh of a form, so I am attempting this in Ajax through Angular.
What information do I need to send to the Laravel controller with Ajax that was being sent to the controller via an HTML form previously?
This is the code in the Laravel controller that handled the file information once it got there. That's what I need to figure out how to send, so I can hopefully reuse this code:
$promotion = Promotion::find($id);
if (Input::hasFile('img_path')){
$path = public_path().'/images/promotion/'.$id.'/';
$file_path = $path.'promotion.png';
$delete = File::delete($file_path);
$file = Input::file('img_path');
$uploadSuccess = $file->move($path, 'promotion.png');
$promotion->img_path = '/images/promotion/'.$id.'/promotion.png';
}
if (Input::hasFile('video_path')){
$path = public_path().'/video/promotion/'.$id.'/';
$file_path = $path.'promotion.mp4';
$delete = File::delete($file_path);
$file = Input::file('video_path');
$uploadSuccess = $file->move($path, 'promotion.mp4');
$promotion->video_path = '/video/promotion/'.$id.'/promotion.mp4';
}
As you can see above, we are converting whatever file we get to a PNG with the file name promotion.png so it's easy to fetch, and we are only accepting .mp4 video format. Because of that, we don't need to worry about checking if the file exists and is it ok to overwrite it. That's why you can see in the code we delete any existing file of that name before saving.
The HTML was just an input with a type of "file:
<input type="file" id="img_path" name="img_path" class="promo-img-path" accept="image/*">
We are using Angular now so I can't just send the above through an HTML form anymore. That's what I need to figure out how to do.
We are two developers just doing our best, so I'm sure there is a better way of doing this. However before I refactor this whole thing, I'm hoping I can use Angular (or jQuery as a last resort) to just send the controller whatever file data Laravel needs in order to make the above code work. The answer may be as simple as "send a PUT to the method in that controller above, but instead of a normal JSON payload, use file info in this format and you can gather that info with..."
I would also appreciate any tips on better ways I can do this in the future.
How to POST FormData Using the $http Service
When using the FormData API to POST files and data, it is important to set the Content-Type header to undefined.
var fd = new FormData()
for (var i in $scope.files) {
fd.append("fileToUpload", $scope.files[i]);
}
var config = {headers: {'Content-Type': undefined}};
var httpPromise = $http.post(url, fd, config);
By default the AngularJS framework uses content type application/json. By setting Content-Type: undefined, the AngularJS framework omits the content type header allowing the XHR API to set the content type. When sending a FormData object, the XHR API sets the content type to multipart/form-data with the proper boundaries and base64 encoding.
For more information, see MDN Web API Reference - XHR Send method
How did you get the file information into $scope.files?
How to enable <input type="file"> to work with ng-model
This directive also enables <input type="file"> to automatically work with the ng-change and ng-form directives.
angular.module("app",[]);
angular.module("app").directive("selectFilesNg", function() {
return {
require: "ngModel",
link: function postLink(scope,elem,attrs,ngModel) {
elem.on("change", function(e) {
var files = elem[0].files;
ngModel.$setViewValue(files);
})
}
}
});
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<h1>AngularJS Input `type=file` Demo</h1>
<input type="file" select-files-ng ng-model="fileArray" multiple>
<code><table ng-show="fileArray.length">
<tr><td>Name</td><td>Date</td><td>Size</td><td>Type</td><tr>
<tr ng-repeat="file in fileArray">
<td>{{file.name}}</td>
<td>{{file.lastModified | date : 'MMMdd,yyyy'}}</td>
<td>{{file.size}}</td>
<td>{{file.type}}</td>
</tr>
</table></code>
</body>
RECOMMENDED: POST Binary Files Directly
Posting binary files with multi-part/form-data is inefficient as the base64 encoding adds an extra 33% overhead. If the server API accepts POSTs with binary data, post the file directly.
See How to POST binary files with AngularJS (with DEMO)
I am trying to select a local json file and load it in my blazor client component.
<input type="file" onchange="LoadFile" accept="application/json;.json" class="btn btn-primary" />
protected async Task LoadFile(UIChangeEventArgs args)
{
string data = args.Value as string;
}
P,S I do not understand , do i need to keep track both the name of the file and the content when retrieving it ?
I guess you're trying to read the contents of a JSON file on the client (Blazor), right? Why not on the server !?
Anyhow, args.Value can only furnish you with the name of the file. In order to read the contents of the file, you can use the FileReader API (See here: https://developer.mozilla.org/en-US/docs/Web/API/FileReader). That means that you should use JSIntrop to communicate with the FileReader API. But before you start, I'd suggest you try to find out if this API have been implemented by the community (something like the localStorage, etc.). You may also need to deserialize the read contents into something meaningful such as a C# object.
Hope this helps...
There is a tool that can help, but it currently doesn't support the 3.0 preview. https://github.com/jburman/W8lessLabs.Blazor.LocalFiles
(no affiliation with the developer)
The input control will give you the location of the file as a full path along with the name of the file. Then you still have to retrieve the file and download it to the server.
Late response but with 3.1 there is an additional AspNetCore.Components module you can download via NuGet to get access to HttpClient extensions. These make it simple:
// fetch mock data for now
var results = await _http.GetJsonAsync<WellDetail[]>("sample-data/well.json");
You could inject the location of the file from your input control in place of the "sample-data/well.json" string.
Something like:
using Microsoft.AspNetCore.Components;
private async Task<List<MyData>> LoadFile(string filePath)
{
HttpClient _http;
// fetch data
// convert file data to MyData object
var results = await _http.GetJsonAsync<MyData[]>(filePath);
return results.ToList();
}
I'm new to Laravel 5.1
Can you guys help me on how to upload files like docx, PDF or image to store it in the database using Laravel 5.1 ?
I browsed a lot of tutorials but not in Laravel 5.1 I'm trying it myself but it didn't work.
NotFoundHttpException in
C:\Loucelle\ _\
_\vendor\laravel\framework\src\Illuminate\Routing\RouteCollection.php line 161:
Can you help me by giving any sample codes?
Your Route:
Route::post('uploadFile', 'YourController#uploadFile');
Your HTML blade:
<form action="{{ url('uploadFile') }}" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit">
</form>
Your Controller:
public function uploadFile()
{
//get the file
$file = Input::file('file');
//create a file path
$path = 'uploads/';
//get the file name
$file_name = $file->getClientOriginalName();
//save the file to your path
$file->move($path , $file_name); //( the file path , Name of the file)
//save that to your database
$new_file = new Uploads(); //your database model
$new_file->file_path = $path . $file_name;
$new_file->save();
//return something (sorry, this is a habbit of mine)
return 'something';
}
Useful resources (these links may expire, so they are only here for reference):
Laravel Requests (like Inputs and the such)
File Upload Tutorial that helped me when I started
So.. This is my code for uploading an image with the Ferris2 frame work. Yay me, it works. However, see how I had to comment out gcs.open(... ? I don't want that commented out. I'd really love to just upload straight to cloud storage using that call, and not having to use anything related to blobs. What's the easiest way to accomplish this given that I'm stuck with using the AClassForm and the ferris framework?
class AClassForm(forms.model_form(AClass, exclude=('image_url') ) ):
image = FileField(u'Image File')
class AClasses(Controller):
class Meta:
Model = AClass
prefixes = ('admin',)
components = (scaffold.Scaffolding, Upload)
Form = AClassForm
admin_list = scaffold.list
admin_view = scaffold.view
admin_edit = scaffold.edit
admin_delete = scaffold.delete
def admin_add(self):
self.scaffold.ModelForm = AClassForm
self.scaffold.form_encoding = "multipart/form-data"
def before_save_callback(controller,container, item):
image = self.request.params["image"]
object_name = blobstore.parse_file_info(image).gs_object_name.split('/')[-1]
upload_settings = settings.get("upload")
url = upload_settings["url"]
bucket = upload_settings["bucket"]
#send to the cloud
#write a task to execute this?
item.image_url = url % (bucket, object_name)
#gcs_file= gcs.open("/".join(["", bucket, object_name]),
# 'w', content_type="image/jpeg",
#options={'x-goog-acl': 'public-read'} )
#gcs_file.write(item.image)#.file.encode('utf-8')) #
#gcs_file.close()
return
self.events.scaffold_before_save += before_save_callback
return scaffold.add(self)
I am not sure how Ferris works internally but you can use cloudstorage directly.
My image storage wrapper, provides resizing and returns a public URL to the upload for serving directly from storage.
import urlparse
from google.appengine.api import app_identity, blobstore, images
import cloudstorage
class ImageStorage(object):
def __init__(self, base_uri):
self.base_uri = "/{}/{}".format(app_identity.get_default_gcs_bucket_name(), base_uri.lstrip('/'))
def put(self, image, name, mime=None, width=None, height=None):
"""Puts an image into the Google Cloud Storage"""
if width or height:
image = images.resize(image, width=width or height, height=height or width)
mime = 'image/png' # resize defaults to output_encoding=PNG
options = {'x-goog-acl': 'public-read'}
with cloudstorage.open(self.make_key(name), 'w', content_type=mime, options=options) as fp:
fp.write(image)
return self.get_url(name)
def get_url(self, name):
"""Gets the url for an image from Google Cloud Storage"""
key = self.make_key(name)
# must be prefixed with /gs for the blob store to know it is from gcs
# https://cloud.google.com/appengine/docs/python/blobstore/#Python_Using_the_Blobstore_API_with_Google_Cloud_Storage
url = images.get_serving_url(blobstore.create_gs_key('/gs' + key))
# s/https/http/ if running under dev_appserver.py
# if not config.isLocal:
# parts = urlparse.urlparse(url)
# secure_parts = ('https',) + parts[1:]
# url = urlparse.urlunparse(secure_parts)
return url
def make_key(self, name):
"""Makes an item name key for Google Cloud Storage"""
return '%s/%s' % (self.base_uri, name)
Usage inside of a subclass of webapp2.RequestHandler. This stores the file with name "image" in the default bucket for your app in cloud storage at path /some/bucket/path/my-image-name.
thumb = self.request.POST["image"]
if hasattr(thumb, 'value'):
gs_base_uri = '/some/bucket/path'
image_storage = ImageStorage(gs_base_uri)
thumb_fn = 'my-image-name'
session_thumb_url = image_storage.put(image=thumb.value,
name=thumb_fn,
mime=thumb.type,
width=300, height=300)
return session_thumb_url
As I understand it, if you're using the Upload component of Ferris you can't escape the Blobstore, but the following comes pretty close. You don't have to use the Form class if you don't want to, I rarely use it myself. So imagine the following Controller:
from ferris import Controller, route
from ferris.components.upload import Upload
import cloudstorage as gcs
from google.appengine.ext import blobstore
import logging
class ImageManager(Controller):
class Meta:
components = (Upload,)
#route
def list(self):
#This just passes the upload URL to use in the form
self.context['upload_url'] = self.components.upload.generate_upload_url(uri=self.uri('image_manager:image_uploader_action'))
#route
def image_uploader_action(self):
# This gets all of the uploads passed in from the form
uploads = self.components.upload.get_uploads()
# This is the raw google cloud object reference. 'myfile' is the name of the upload field in the html form
file_gcs_obj_name = uploads['myfile'][0].cloud_storage.gs_object_name
# This is the blobstore key just for giggles
file_blobstore_key = uploads['myfile'][0].key()
# This will get rid of the preceeding junk you don't need i.e. "/gs/yadda/yadda"
clean_file_name = file_gcs_obj_name[3:]
# This is the name of the file as it was uploaded by the end-user
file_name_friendly = uploads['myfile'][0].filename
# This is the actual file, with this you can do whatever you want
the_actual_image = gcs.open(clean_file_name,'r')
# The file name by default is long and ugly, lets make a copy of the file with a more friendly name
new_filename = '/mydomain.appspot.com/'+file_name_friendly
gcs.copy2(clean_file_name,new_filename)
# We can generate a serving URL by using the blobstore API
valid_blob_reference = blobstore.create_gs_key('/gs'+new_filename)
file_serving_url = images.get_serving_url(valid_blob_reference)
logging.info('the serving url is: %s'% file_serving_url)
# delete the original image from cloud storage
gcs.delete(clean_file_name)
# Delete the original image from blobstore
blobstore.delete(file_blobstore_key)
# Close the file
the_actual_image.close()
return 'Done. go check the cloud storage browser'
Now all you need is the HTML form. You can use something like this:
{% extends "layouts/default.html" %}
{% block layout_content %}
<form name="myform" action="{{upload_url}}" method="POST" enctype="multipart/form-data">
<input type="file" name="myfile" id="fileToUpload">
<input type="submit" value="Upload File" name="submit">
</form>
{% endblock %}
Ferris is still going to place a file in the blobstore but you can delete it after you've used the cloudstorage.copy2() function. That function is fairly new so remember to update your cloudstorage package, you can download the latest copy from Google or Pypi (https://pypi.python.org/pypi/GoogleAppEngineCloudStorageClient/1.9.22.1)
Hope this helps.
I have the this function which it has been written in html. you put a md5 value in the textbox and hit the button to start searching.
<form action="http://www.virustotal.com/vt/en/consultamd5" method="post">
<input name="hash" >
<input type="submit" value="get MD5">
My question is how do I do the something like the html function I have mentioned above, open an url, post something and see the results in the opened page?
For example in winforms put an md5 value in an textbox hit the button to start searching.
Use the HttpWebRequest as the following,
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://www.virustotal.com/vt/en/consultamd5");
req.Method = "POST";
Stream s = req.GetRequestStream();
StreamWriter sw = new StreamWriter(s);
sw.Write("hash=yourtexthere");
sw.Flush();
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
Or you can use MD5 in .net which is located in System.Cryptography.MD5 instead.