Downloading a docx file in CakePHP - php

I am trying to make a download action that downloads a Word doc generated in the 'download' controller using PHPDOCX. So far PHPDOCX is able to save the desired .docx file in the correct folder, but something goes wrong when I try to download it. Since Media Views were deprecated, I must use the CakeResponse file method as suggested in the CakePHP 2.x Cookbook:
// In the controller:
$this->response->file($file['path'], array('download' => true, 'name' => $filename));
return $this->response;
I was able to use this method for to export an RTF with no problem (the RTF was generated using PHPRTFLite), but when I use the method for a .docx file using PHPDOCX I receive the following error in Firefox:
The character encoding declaration of the HTML document was not found
when prescanning the first 1024 bytes of the file. When viewed in a
differently-configured browser, this page will reload automatically.
The encoding declaration needs to be moved to be within the first 1024
bytes of the file.
I would like to use a document generator that accepts HTML, which is why I chose PHPDOCX. Considering the above error, I set off to define the headers and content-type using the following method:
$this->response->header(array('Content-type'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document'));
But I still receive the same error in CakePHP:
The requested file APP/files/info_sheets/filename.docx was not found or not readable
One thing I was thinking is that PHPDOCX sends many errors when it generates the document and this is interfering with the Mime-type or encoding. But according to the 2.x Cookbook:
Headers are not sent when CakeResponse::header() is called either.
They are just buffered until the response is actually sent.
Another idea is that I need to set the character encoding in the header right after the content-type:
$this->response->header(array('Content-type'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=utf-8'));
But this results in garbled text.
Does anyone have any ideas how to resolve this? The "download.ctp" view file is currently blank. Please let me know if you need additional information about this issue.
Thanks!
Chris

First of all, you might try to disable autoRender, otherwise CakePHP might still try to render your view and layout;
$this->autoRender = false;
Also, haven't tested it, but have you tried this to set the header:
// register the type
$this->response->type(array('docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'));
// set the type for the response
$this->response->type('docx');
See the documentation:
http://book.cakephp.org/2.0/en/controllers/request-response.html#dealing-with-content-types

You can modify the media.php file in the core of the framework and add the mime-type to the array that have the types.
Eg:
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'

Related

using PHP to remove the extension from a file and then downloading it

I recently had a asked a question very similar to this one, however after evaluating that I did not explain it in the best way I have come back once again explaining it in a greater manner.
So, I am creating a system that will gather data from a MySQL database and use a unique id to download a file, however depending on the value of a column within that database called type, this file could be anything from a png file to an xml file. What I am currently doing is trying to download these files WITHOUT any extension.
As an example to maybe make this easier to understand, a file named image.png would be converted to just image and then downloaded.
With this you could rename the file to image.png again on the local machine and view the image.
This may seem very inefficient to most reading this but for my current situation it's all that will work.
How could I remove a files extension and then download it? (in php)
Thank you in advance.
Just use headers to specify response type.
$filepath = '/wherever/the/file/is.png';
$filename = 'new-cool-name';
header('Content-Type: whatever/content-type-is');
header("Content-disposition: attachment;filename=$filename");
readfile($filepath);
This basically sends a response with specified content-type as an attachment and the body of the attachment contains the file contents. If you never sure what's the content type is, then just use application/octet-stream
Usually when you set out to push a file for downloading from a serverside script, you do so by utilizing http headers like https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
The filename of the downloadable file is specified in that header
Okay so to remove an extention from a file you could do is
$withoutExtion = preg_replace('/\\.[^.\\s]{3,4}$/', '', $youfilename);
...followed by your file download code

How to change the Title attribute of a file using PHP

Users upload PDF files using my PHP application and I store them on S3. At some later point other users view the files, which I display 'inline' in their browser.
The problem is that the 'Title' attribute of the PDF is displayed in teh browser tab where the web site title would normally be displayed. As it is set by the user who did the original upload, it is arbitrary, and I therefore need to change it. How do I do this?
I thought that Title was an extended attribute of the file, however installed Ubuntu's xattr, and when I run it on the file, it returns nothing, so perhaps I am mistaken.
When I view the object metadata on S3, there is no mention of a Title attribute, so I don't know where/how it is stored on S3.
My preference would be to rewrite the Title attirbute using an OS call, rather than installing another PHP extension (such as xattr).
EDIT: Here is the Laravel controller method which returns the response
public function displayFile($id)
{
$headers = ['Content-Type' => 'application/pdf', 'Content-Disposition' => 'inline'];
return response(Storage::disk('private')->get("files/{$id}.pdf"), 200, $headers);
}
When you say 'inline' what exactly do you mean? What you are describing seems more like you are pointing them to the document url. In this case, the title will be the one contained in the PDF, which only some PDF editor could change. I know of none that will not break files (especially ones with interactive content) BADLY for PHP. If you have access to native apps, you can try using exiftool: https://askubuntu.com/questions/27381/how-to-edit-pdf-metadata-from-command-line
What you might want to do is actually display the document inside a HTML file, like this:
https://www.w3docs.com/snippets/html/how-to-embed-pdf-in-html.html
Note: do extensive testing for various browsers, especially mobile; PDF embedding is notoriously quirky in mobile browsers.
You should be able to add an arbitrary filename to Content-Disposition for inline viewing, just as you could if you were downloading. Try something like this:
$headers = ['Content-Type' => 'application/pdf', 'Content-Disposition' => 'inline; filename=\"WhateverYouWantTheUsersToSee\"'];
(Don't actually know whether you need to escape those quotation marks; if not, take out the backslashes.)
The problem is that to set the title, the title must set into the pdf, but there is a workaround ( see explanation )
Explanation:
The page with target "_blank" attribute, set the file names base on the last part of the url. So if the url is my.site/32/55 , the html title is 55.
The workaround is to set the file name as the last part of the url
1) Web.php
This is the most important part. To give the page the pdf title, set the title you want as the last param
Route::get('/pdfSee/{fileID}/{htmlTitle}', 'FileController#viewInTheBrowser')->name('file.see');
2) Controller
public function viewInTheBrowser(File $file){
$basePath = 'public/myFolder/';
return response()->download(storage_path("app/".$this->basePath. $file->file_system_path), $file->file_name, [], 'inline');
}
3) View
Download
As you can see, we pass in the route file.see the actual file name as last param, so wen the html page is open, it takes the last param ( the file name ) as html page title

Joomla Zoo download element wrong content-type or mime-type for vcard (.vcf)

My client is using Joomla 3.7.2 and they are using the Zoo component by YOOTheme. They have created an App I believe it's called in jargon and they've added a property (element) where you can download a file.
The App is an article type app and they've used the default download element. I added the permissions to upload certain files and I've uploaded a VCF file (a vCard file).
The problem occurs when I download that file. Joomla seems to add the Content-Type: 'text/x-vcalendar'. This should be 'text/x-vcard'. I have no idea where to change this.
I have added this mime-type to my .htaccess, so when I directly link to the file, apache does send the right content type header. Therefor I know that the problem lies in either joomla or a PHP function that returns the wrong mime type.
Where do I change the mime-type for these files?
I finally found it. There's a function in the file: /administrator/components/com_zoo/framework/helpers/filesystem.php
Within this file there's a function called getMimeMapping. In it is an array with all the file extensions and mime types used per extension:
$mimes['vcf'][] = 'text/x-vcalendar';
$mimes['vcs'][] = 'text/x-vcalendar';
$mimes['vct'][] = 'text/x-vcard';
So apparently if I use the extension vct, it will output the correct Content-Type.

CodeIgniter. Download Helper. Memory usage question

Question about this helper http://codeigniter.com/user_guide/helpers/download_helper.html
If, for example, program.exe weights 4 GB, will it take a lot of PHP memory for reading and delivering that file?
$data = file_get_contents("/path/to/program.exe"); // Read the file's contents
$name = 'software.exe';
force_download($name, $data);
force_download function just set the proper HTTP headers to make the client's browser download the file. So, it won't open the file, just pass it's URL to the client.
Check the helper source code, if you need: https://bitbucket.org/ellislab/codeigniter-reactor/src/31b5c1dcf2ed/system/helpers/download_helper.php
Edit: I'd sugest creating your own version of the helper, and, instead of using strlen to get the file size, use the php function filesize, which takes only the file name as argument and returns the size in bytes.
More info, at http://www.php.net/manual/en/function.filesize.php
Yea... that could get... bad...
file_get_contents reads the entire contents of a file into a string. For large files, that can get, well, bad. I would look into readfile. Please remember too -- since CI automatically caches when you are loading a view, that means there will be no discernible benefit to readfile if it is used in a CI view. It would almost be better to handle this with an external script or by outputting directly from the controller and not calling the view at all.

PHP to consume webservice that needs xs:base64Binary

I've got a webservice which expects a parameter of type "xs:base64Binary" - this is a file to store in the database.
I'm trying to consume the service using PHP 5's native webservice classes. I've tried a few things:
// Get the posted file
$file = file_get_contents($_FILES['Filedata']['tmp_name']);
// Add the file, encoding it as a base64
$parameters = array("fileBytes" => base64_encode($file));
// Call the webservice
$response = $client->attachFile($parameters);
The result is an error saying "Bad Request." If the file is a text file and I don't base64_encode, it works fine. Problem results when posting a binary file such as an image.
Anyone know the trick here?
EDIT 1
Also problematic is if I encode the text file, it seems to work but of course it's encoded and ends up being junk once downloaded and viewed again (i.e, the text is encoded and doesn't seem to get de-coded by the server).
As far as I know, base64_encode() should be doing the job.
Are you 100% sure $file contains something? Have you made a dump?
Ok, so it seems there is no need to use base64_encode. The file_get_contents already puts it into the required format.
Additionally, the problem was because I had the server side config setting for the maxArrayLength too low.

Categories