symfony + AJAX how to upload files embedded in javascript JSON objects? - ajax

I have a client uploading files embedded in JSON objects because each one of these files has attached metadata.
The problem is that I do not know how many files they will upload so I need something dynamic
at the moment I have a fileList javascript object that contains sub objects that looks like this:
{
file1: null
meta1: null,
meta2: null,
etc...
}
{
file2: null
meta1: null,
meta2: null,
etc...
}
I upload it like this:
formData.append('files', this.fileList);
but in symfony, I do not know how to process this particular situation
If I look in the profiler I get something like this :
files "[object Object],[object Object]"
and $files = $request->files->get('files'); gives null
Is there another way to decode the data? it is there but I can't read it :(

If you have a file to upload, one per metadata row, I'd send the file separately when it's selected in the form (I like BlueImp for this, but there are others) with Ajax and pend it to a directory (with a cleanup script that deletes them when 24hr old, S3 does this nicely). Then return that path to the form, put that in your JSON-ified body you submit, then you have your metadata, which happens to include it's pending filepath. Move that pending file on submit and keep that new reference when you save the row or whatever. Voila.
So:
files[][filename].onchange: [/* Upload file to pending, return pending path */]
With return path, pending/ad32sY3KJ.png, submit
"files": [
["file":"`pending/ad32sY3KJ.png`","meta1":"Root Beer"],
["file":"`pending/34dks3DWf.png`","meta1":"Cat"]
]
Then your router handler has an array, so Content-type: application/json works as expected, although you'd use:
$body = \json_decode($request->getContent(), true);
Instead.

Related

Generate Excel file with PhpSpreadsheet in Codeigniter from a view

I am trying to generate an Excel file with CodeIgniter and the PhpSpreadsheet library from a view. The reports that I need to make are not a list but much more complex and I can generate them more quickly with a view and sending parameters. This is my code:
$data = $this->model->bringdata();
$view = $this->load->view("data_view", $ data);
$spreadsheet = new Spreadsheet();
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Html($spreadsheet);
$writer-> save($view);
And the following error is shown
Severity: Warning
Message: fopen (): Filename can not be empty
Filename: Writer / Html.php
Line Number: 160
In the PhpSpreadsheet documentation it shows that an html page must be explicitly sent:
$writer->save("05featuredemo.htm");
Is there any way to do what I need?
Thanks for the help
It's a simple solution, you need to pass true to the third argument of load->view in order for it to return a string rather than sending it to the browser.
$view = $this->load->view("data_view", $ data, true);
Added after comment
I made the mistake of not looking into how the Html writer works.
The HTML writer writes a spreadsheet as an html file. It does not create a spreadsheet. As I understand it (and I might be mistaken) you can use \PhpOffice\PhpSpreadsheet\Reader\Html to read an html file into a spreadsheet.
In your case I think you will have to save the string returned from $this->load->view() to a temporary file. CodeIgniter's file_helper might be useful here.
You then read the temporary file to create a spreadsheet. After that you can use $writer to save the spreadsheet somewhere as any of the file types the PhpSpreadsheet supports.
$view = $this->load->view("data_view", $data, true);
$this->load->helper("file");
$fileName = "temp_file_name.html";
$path = "full/path/to/some_writable_folder/";
$path_file = $path . $fileName;
if (write_file($path_file, $view))
{
//create spreadsheet the temp html
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Html();
$spreadsheet = $reader->load($path_file);
//write out to html file
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Html($spreadsheet);
$writer->save($path."05featuredemo.htm");
//delete the temporary file
unlink($path_file);
}
else
{
//handle the failure to write the temp file
}
I haven't tested this and I'm not sure you really want to save to an html file, but I think the above is close to the answer.
Second addition
If you want to save .xlsx files you need an Xlsx writer. Use the following instead of what's shown above.
//write out to excel file
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
$writer->save($ path. "doc.xlsx");
I confess that I have never used, or considered using the html reader so I'm not sure you'll get what you want. I honestly think that creating an html table so you can import it into excel is probably doing it the hard way.

generating multiple pdf document and merge into one

This is my controller function where i am running a loop to create multiple document pdf
and merge into one.
public function tick_pdf(){
$tt='';
$name="iftekhar";
$title="Event Football";
$num=4;
for($i=0;$i<4;$i++){
$this->pdfHeader($row->EventId);
$this->pdf->fontpath = 'font/';
//$this->pdf->AddPage();
$this->pdf->Ln(10);
$this->pdf->SetFont('Arial','B',12);
$this->pdf->Cell(10);
$this->pdf->Cell(60,10,"Name",0,0,'L');
$this->pdf->Cell(10,10,":",0,0,'L');
$this->pdf->MultiCell(60,10,$name,0,1);
$this->pdf->SetFont('Arial','B',12);
$this->pdf->Cell(10);
$this->pdf->Cell(60,10,"Title",0,0,'L');
$this->pdf->Cell(10,10,":",0,0,'L');
$this->pdf->MultiCell(60,10,$title,0,1);
$this->pdf->SetFont('Arial','B',12);
$this->pdf->Cell(10);
$this->pdf->Cell(60,10,"Number",0,0,'L');
$this->pdf->Cell(10,10,":",0,0,'L');
$this->pdf->MultiCell(60,10,$num,0,1);
$this->pdf->SetFont('Arial','B',12);
$this->pdf->Cell(10);
$this->pdf->Cell(60,10,"Date",0,0,'L');
$this->pdf->Cell(10,10,":",0,0,'L');
$this->pdf->MultiCell(60,10,$date,0,1);
$tt.=$this->pdf->Output('', 'S');
}
echo $tt;
}
but I am gettiin an error in browser
"Undefined index: data
Filename: libraries/fpdf.php
Line Number: 1659" I am using fpdf for generating pdf
If you need to create multiple PDF documents you will need several class instances. Actually you're working with only one instance.
Also it is not possible to concatenate a PDF document by simply concatenating their bytes ($tt .= ...). Generally it is not possible to send multiple PDF documents to the client in a single request.
If you want to create multiple pages, just remove the comment before AddPage(), delete the variable $tt and move the Output() call outside of the loop.

Write in a file Json already exist

I found this page How can I pretty-print JSON using node.js? and I think it's useful, but I have one question: I have a page that give a result from a request sparql in an array, and I want to take just one line of this results with a button "add" that is insert in the last column of the line, and when I take the line in Json I want to write it in a file json that already exist with other data. The button call the next function:
function add(param) {
res= param;
$.ajax({
type: "POST",
url: "....",
data: { nom:resource,abstract:resume,photo:src,indice: res ,fichier:$("#myselect" ).val()}
})
.done(function( msg ) {
alert( "ajout réussie"+msg);
window.location.reload();
});
};
Where res is the index for the line that I want to add, and data all data I need to add.
So I want to know how I can change this code to use the last code posted by "Larry Battle". I have to put his code in a file "add.js" and I call this file in url? Or How?
Link for my example: https://www.dropbox.com/s/noyh1ltwljlpevw/Capture%20du%202014-05-01%2019%3A05%3A04.png
The easiest way might be to require the original json file, add the new data in memory, then save the object back as a pretty json file (overwriting the original if you like).
I'm not sure what you meant by "res is the index of the line I want to add", so I'll assume it's going to be the property name in the javascript object that you serialize to JSON. So in general it'd look something like this:
var fileData = require('/path/to/jsonData.json');
// fileData is now a JS object that was parsed from the json file); this is a sync operation.
fileData[res] = data; // data object from your existing code.
// write fileData to a JSON file like you were going to do before.

Accessing temporary file from upload in django view

Just as the title says, I want to know how to access the data from the temporary file stored by Django, when a file is uploaded, inside a view.
I want to read the data uploaded values so I can make a progress bar. My methodology is to perform a jquery getJSON request:
function update_progress_info() {
$progress.show();
$.getJSON(progress_url, function(data, status){
if (data) {
var progress = parseInt(data.uploaded) / parseInt(data.length);
var width = $progress.find('.progress-container').width()
var progress_width = width * progress;
$progress.find('.progress-bar').width(progress_width);
$progress.find('.progress-info').text('uploading ' + parseInt(progress*100) + '%');
}
window.setTimeout(update_progress_info, freq);
});
};
where progress_url is the view I have that handles the uploaded file data:
# views.py (I don't know what to do here):
def upload_progress(request):
for line in UploadedFile.temporary_file_path
response = (line)
return response
Django handles uploaded files with UploadHandler defined in settings.py with this name FILE_UPLOAD_HANDLERS that defaults to this tuple:
FILE_UPLOAD_HANDLERS =
("django.core.files.uploadhandler.MemoryFileUploadHandler",
"django.core.files.uploadhandler.TemporaryFileUploadHandler",)
The behavior with file uploads is that if the file is less than 2.5 mg then it will be kept on memory, hence, they will not be written in disk as temporary files.
If the file weights more, it will be written in chunks in the FILE_UPLOAD_TEMP_DIR in the settings.py. That's the file you'll have to query to know how many bytes have been uploaded.
You can access the uploaded/uploading files through your request variables in views like this: file = requests.FILES['file'] . There, file variable will have the type UploadedFile which contains a method temporary_file_path with the address of the file in the disk being uploaded. (Note: only files larger than 2.5 mg will have this methods) so there you may get the size of the file being uploaded.
Another way to do this is create your own UploadHandler like a ProgressBarUploadHandler and add it to your file upload handlers. This is the way the docs recommend it. Here are some snippets and tutorials for doing it.
If you need any more info the doc is really well documented.
I hope you find this helpful. Good luck.

casperjs download file without specifying url

Is there any way to download CSV file with casperjs without specifying download URL? I am trying to download CSV file whose URL is dynamically generated when I click the download button. So, I may not be able to use download() well under the situation.
For the record, it's already possible using 'resource.received' event.
If you receive header like this one:
Content-Disposition: Attachment; Filename="ExportData.csv"
The file generated can be downloaded using following event listener:
casper.on('resource.received', function(resource) {
if (resource.stage !== "end") {
console.log("resource.stage !== 'end'");
return;
}
if (resource.url.indexOf('ExportData.csv') > -1) {
console.log("Downloading csv file");
this.download(resource.url, 'ExportData.csv');
}
});
I have found a solution for that. It is not very clean but it works :
You need to build an global array, which associates every resource.received having a filename attached.
fileInfos[url]= parse_filename_from_responseHeader(resource)
If url is the resource you want to download, try open(url) first. This will trigger the resiyrce.received event, parse the header and update the global array.
Now, before launching the casper.download(url), look for fileInfos[url].
You will find the filename corresponding to the url in the fileInfos array.
I can elaborate on the solution if needed, but since the question is already a few years old,
I'll wait for the next poke to elaborate.
This won't be possible until this phantomjs issue will be solved http://code.google.com/p/phantomjs/issues/detail?id=52
What I would do is something like this but I know the filename that I am gonna receive:
this.waitForResource(function check(resource){
res = resource;
// regular expression to test
return /thefilename/.test(resource.url);
}, function(){
this.echo("Resource found: " + res.url);
// download the file
this.download(res.url, path);
}, null, 10000);

Resources