Images are always served with name "unnamed.jpg" in Google App Engine - php

I am working on a PHP app on Google App Engine standard environment.
I upload an image to the app's associated bucket, then use this code to serve the image:
use \google\appengine\api\cloud_storage\CloudStorageTools;
// ...
$path = "gs://my-app.appspot.com/the_image_name.jpg"
$imageUrl = CloudStorageTools::getImageServingUrl($path, ['secure_url' => true, 'size' => 0]);
header("Location: $imageUrl");
There is of course a redirection to a page like this:
https://lh3.googleusercontent.com/<some_hash>
The image displays correctly, but in the title of the browser it says "unnamed.jpg", and when I try to save the image to my computer the default name appears as "unnamed.jpg". This happens every time I upload an image, no matter its actual name, or if I do upload it through my app using the API or if I upload it directly to the bucket through the web cloud console.
Is there any way in which I can specify what name is used when serving the image?

Did you set the headers: 'Content-disposition', 'Content-Transfer-Encoding', & 'Content-Type'

CloudStorageTools::getImageServingUrl uses googleusercontent.com which is a "sandbox" and therefore you can't change the name of the file served.
I suggest you to take a look in CloudStorageTools::serve method where you will be able to set the name of the file with save_as parameter. Please note that the type is string and not boolean as it's mentioned in the documentation and serve will take some app engine compute time.
The code should look like this:
use \google\appengine\api\cloud_storage\CloudStorageTools;
// ...
$file_name = "gs://my-app.appspot.com/the_image_name.jpg"
$options = ['save_as' => 'the_image_name.jpg'];
CloudStorageTools::serve($file_name, $options);

Related

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

Generating PDF with dynamic image from storage stalls in Laravel

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).

Get gps metadata from image in dropbox using PHP

I am trying to get specific metadata of an image located in dropbox using PHP and the Dropbox API.
After I connect to dropbox and list the images, I do this:
$md = $dbxClient->getMetadata($path);
print_r ($md);
Where the $path is the directory to my image. This works perfectly but I need to get more metadata regarding GPS location. In the Dropbox API (general view for Python, PHP, Java etc.) it says I have to set "include_media_info" to true to get gps metadata.
Going to the PHP part it has the function GetMetaData() with only one parameter: string
($path The Dropbox path to a file or folder).
Is there a way to get detailed metadata using the Dropbox API for PHP?
As you noted, the PHP library doesn't support the include_media_info parameter, so you'd need to modify the source code of the library to add support.
E.g. you could add this method:
function getMetadataWithMediaInfo($path)
{
Path::checkArg("path", $path);
return $this->_getMetadata($path, array("include_media_info" => "true"));
}
I had a look at the source, try this:
$md = $dbxClient->_getMetadata($path,array("list" => "true"));
or edit the core getMetadata and change its hard coded parameter list to true

PHP Google App Engine permanently delete Image from Cloud Storage

I'm using GAE version 1.9.0 and I want to delete an image from the data storage and upload another image to its location. This is how I'm doing it right now.
unlink("gs://my_storage/images/test.jpg");
move_uploaded_file($_FILES['image']['tmp_name'],'gs://my_storage/images/test.jpg');
And then I want to get the Image serving URL of the latest uploaded image, and I do it like this.
$image_link = CloudStorageTools::getImageServingUrl("gs://my_storage/images/test.jpg");
The issue is, when the name of the deleted image("test.jpg") and the uploaded image("test.jpg") is the same, the old file is served when I call for the newly uploaded file(I think it is cached.)
Is there anyway I can permanently delete this file without caching it?
You should probably delete the original serving URL before creating another with the same name.
There's a deleteImageServingUrl() method in CloudStorageTools that you can use to do this.
Here it is how to do in php laravel.
$object = $post_media->media_cloud;
$objectname = substr($object,48,100);
$bucket = Storage::disk('gcs')->delete($objectname);
Here in $object i get google cloud image url from db
Then we take only object name from that url, by substr.
Since you have given in your config Storage class as Storage::disk('gcs')
so this will call the function delete by taking the objectname.
Hope it helps anyone.
Note : For multiple images either pass an array of objects, or repeat it foreach loop.

Google Drive SDK (PHP Client Library) - Upload file but unreadable on the Google Drive UI

Here is my code to upload a file:
private function addFile(File $file, $folderProject, User $user) {
$fileToUpload = new Google_DriveFile();
$fileToUpload->setTitle($file->getName());
//set mime type
$fileToUpload->setMimeType($file->getMimeType());
//build parent and set id
$parent = new Google_ParentReference();
$parent->setId($folderProject->getId());
//set parent to file
$fileToUpload->setParents(array($parent));
$data = file_get_contents($file->getPath());
$createdFile = $this->service->files->insert($fileToUpload, array(
'data' => $data,
'mimeType' => $file->getMimeType(),
));
}
When I upload for example a docx using this PHP code the file append to be unreadable on the Google Drive website (it shows up the XML structure of the docx) and it is showing up like this in my Google Drive folder:
And when i try to upload a docx directly through Google Drive UI it showing up like this (what i want):
I'm pretty sure that the problem is coming from the fact the Google
Drive UI tries to open the file in a different way because i uploaded
it through my app, but i don't want that :)
(i have the same problem with other kind of files)
I tried to set the parameter 'convert' = true in the array but then i got this error during the upload:
..convert=true&uploadType=multipart&key=AI39si49a86oqv9fhb9yzXp7FCWL-cSqwFiClHZ‌​qS3Y3r9Hw8ujtSNlZEWZyFKBp_id7LUyFaZTJ97pMeb0XqHznycK7JJ9o_Q:
(500) Internal Error
Documentation: https://developers.google.com/drive/v2/reference/files/insert
=> But anyway i don't think to convert is the right solution, i just want to be able to see the content as if i uploaded the file through the Google Drive UI
If i open the docx from my Google Drive Sync folders and I edit and save it, I will be able to see it through the Google Drive UI (showing with the W logo)
I also getting the same problem.
But the difference is that , I am uploading pdf and able to view pdf in google drive UI.
I need to automatically convert it to google doc format by api code after adding new pdf.
If I change $mimeType = 'application/vnd.google-apps.document'; then got below error
https://www.googleapis.com/upload/drive/v2/files?convert=true&uploadType=multipart: (400) Bad Request
if I add optional parameter
$createdFile = $service->files->insert($file, array(
'data' => $data,
'mimeType' => $mimeType,
'convert' => TRUE
));
Then no change , only pdf upload no conversion takes place.
do u have any suggestion , where I need to exactly add for convert parameter ?

Categories