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
Related
I want to show an img like this:
http://picviewer.umov.me/Pic/GetImage?id=92013681&token=ee103380297bbb2df0d8855949d791df
How should i use php to show the img with dynamic parameters?
You need to set the proper content type headers and then stream the binary data.
$imagepath = '/path/to/file';
header("Content-type: image/jpeg");
echo file_get_contents( $imagepath );
First i'll explain what does that URL do: it's configured to point to a script, or class->function, that manages the searching in the database, for the real path, the path you want to hide for the user, then returns the image to the request.
That said, in two steps, what you have to do is the following.
Check how to customize your url, this could be a start:
How to create friendly URL in php?
create your custom url pointing to a script or class/function like this:
Return a PHP page as an image
Thats, all... Assuming that you already have the images/database covered of course. if not, well you'll have to make the necessary database and tables...
I have an issue with a view and generated content to produce a PDF. At the moment, I've been working with niklasravnsborg\LaravelPdf (a wrapper for mPDF, because of an issue with another PDF writer I was working with beforehand), which turns out nice PDFs that are of the quality that I want.
I have never had an issue with images inside of the view before with this PDF writer though, but I must admit that they were with images that had been set-up inside the view already (like a logo, rather than say an employees photo).
My issue arises in a way that has at least allowed me to track down the issue a little better.
From my controller, I get the following:
$employeeMedCert = $employee->attachments()->where('category','Medical Examiners Certificate')->orderBy('endDate','desc')->limit(1)->get();
And then in my blade I have the following:
#foreach($employeeMedCert as $med){
{{Storage::url($med->attachment)}}
#endforeach
Now, with this current setup, I get the public path of the attachment, without any issue at all.
However, if I do the following:
#foreach($employeeMedCert as $med){
<img src="{{Storage::url($med->attachment)}}">
#endforeach
It stalls my Laravel to a point where I have to reset the server and hasn't generated anything.
I'm not sure what the issue is, like I said, I've had no issues with images before and the images I am referencing dynamically aren't large by any means (300 - 600 kB), so I am not sure where the issue actually is.
Upload controller action:
$path = Storage::putFile('public/employees', new File(request('file')));
employeeAttachment::create([
'attachment' => $path,
'attachmentType' => Storage::mimeType($path),
'category' => $request->type,
'endDate' => $request->dueDate,
'date' => $request->date,
'employeeID' => $employee,
'createdBy' => Auth::id()
]);
The big clue for this problem is that in html <img> tags do a get request when they are run in html. This means you could be having a permission error.
You can check this by opening your devtools in chrome and checking out your server requests in any website that has an image tag.
Following things to check (assuming you are using a basic storage e.g. not using AWS):
Is image in your public folder or have you correctly created your sym link: https://laravel.com/docs/5.6/filesystem.
If your files are public can you navigate to it in the browser?
Have you tried using the url instead of going through storage? e.g. <img src="{{base_url() . $med->attachment)}}"> (assuming $med->attachment is a file path).
Assuming it's a public file you shouldn't have to go through the Storage facade to access it. Let me know if this points you in the right direction.
The purpose of the Storage facade is to save files and get files and load them into a php variable. Currently you are loading the file from the server and then pointing your image tag to the file and not to the url of where the image is stored.
Putting in a valid url into the img tag should solve your problem (shown in 3 above).
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'
The following problem I can't really wrap my mind around, so really if you guys can't be bothered to supply the entire code some tips leading in the right direction would be great!
So, I have a script where users can upload images to a server. PHP takes care of validating the file and saving it using a new filename in another folder, neither known by the client. Now, the client should be able to see the uploaded image, in html simply:
style="background-image:url('testimagegif.gif');
But preferably the client should not be able to see the path nor the file name of the image saved on the server. I know about using header('Content-type: ... for forcing the client browser to download files, but I do not see how this, nor any similar solution could be applied to this case. Same goes for readfile. If I use it the browser simply downloads the image, not placing it in the html.
You should probably be moving the files into a publicly readable folder on your webserver if you want to serve them.
Otherwise, you'll need something like readfile()
There are two options for this, you could use the data protocol, which would embed the whole image into the URL of the background ( this isn't recommended if the image is bigger than a few kb. ) or you can use a script to present the image by encoding or recording a unique key for the image, eg bg.php?id=4323-34442-3432-4532 which checks a db for the id to retrieve the file path then echoes the content with the right content type.
Some examples;
based on the Data URI wikipedia page
Data URI Method
Assuming a function like this;
function data_uri($fileID) {
$fRecord = mysql_fetch_array(
mysql_select("SELECT filePath, mimeType from fileTable WHERE fileID = " $fileID . ";")
);
$contents = file_get_contents($fRecord['filePath']);
$base64 = base64_encode($contents);
return "data:$fRecord['mimeType'];base64,$base64";
}
Then in your html/php page you'd have the following snippet
style="background-image:url('<?php echo data_uri($fileID);?>'
PHP Image Dump
Assuming a function like this;
// Given a filename and a mimetype; dump the contents to the screen
function showDocumentContent($fileID){
$fRecord = mysql_fetch_array(
mysql_select("SELECT filePath, mimeType from fileTable WHERE fileID = " $fileID . ";")
);
header( 'Content-Encoding: none', true );
header( 'Content-Type: ' . $fRecord['mimeType'], true );
echo readfile( $fRecord['filePath'] );
}
Then in your html page you'd have this;
style="background-image:url('image.php?fileID=123')
In the first case, images larger than a few KB will result in equally large HTML pages, and may not be supported in browsers consistently. In the second case, you'd effectively have created a php script that is pretending to be an image. In both cases, the real path to the binary files on your server is abstracted away by storing a mapping in a database.
If you store the paths to the files somewhere like a database or a file, you can use readfile() to output the file once you retrieve the path.
Combine that with the content-type header, and set the background-image URL to the PHP script with the correct query string like so:
style="background-image:url('script.php?img=30382');"
You must expose some path to the client, because their browser has to access the file. You can use your webserver config to serve at an indirected location, or serve the image with PHP and have the real path in a call to readfile()
This is continued from my original question (http://stackoverflow.com/questions/10133976/getelementsbytagname-specific-links-only) which I got resolved but now facing different issue.
I'm implementing Anarchy player on my site and problem is that script stores files outside the domain root so links to them are in format like ( http: // mysite.com/mod/file/download.php?file_guid=fileID) which is fine for the player, it still plays the file but I need to separate files by type.
Look at the javascript code below, "if(o.href.match(/.mov$|.mp4$|.m4v$|.m4b$|.3gp$/i)" part, if I understand it correctly it says if file extension is .mov, .mp4, etc. than include that player. But since link is not in standard format with file name and extension it does not recognize it.
How to change that "if(o.href.match" to something that would distinguish what type of file it is?
I can pull file full name with extension in text format via PHP code and maybe wrap it in or div and that use if...div.match(...?
Link to video file is already inside div block id "video"
<div id="video">
</div>
Here is javascript:
var all = document.getElementById ( "video" ).getElementsByTagName ( "a" );
for (var i = 0, o; o = all[i]; i++) {
if(o.href.match(/\.mov$|\.mp4$|\.m4v$|\.m4b$|\.3gp$/i) && o.className!="amplink") {
Thank you so much for any suggestions.
It's not always possible to decide upon the filetype of a file just by looking at the filename. A better approach is to look at the Content-Type header (in case of an HTTP resource) or the MIME-type (which is essentially the same thing).
It's still possible to send a bad Content-Type so perhaps there is a way to identify the filetype by looking at the first few bytes? I know PNG starts with a very obvious indicator.