3
votes

I have an app that lets users upload an image, and I want other users to be able to see that image.

I am using the CloudStorageTools::createUploadUrl method to allows users to upload via POST. I am then taking the uploaded file and using move_uploaded_file to store it on Google Cloud Storage.

Then, I am using CloudStorageTools::getPublicUrl to get the URL for the file. It returns the correct URL, but the file is not publicly accessible so I get a XML error response "AccessDenied".

I know this is because the file isn't shared publicly, but I'm not sure how to make it public after it gets upload.

I tried passing in a "acl=public-read" option to createUploadUrl, but it returned an error of unknown option.

I see an example of how todo this on this page: https://developers.google.com/appengine/docs/php/googlestorage/public_access however, my workflow requires me to allow normal POST uploads using the createUploadUrl method as shown here: https://developers.google.com/appengine/docs/php/googlestorage/user_upload

How do I make user uploaded files automatically publicly accessible?

4
I'm thinking the only way todo this is to use the temp uploaded file $_FILES['myfile']['tmp_name'], and store it to Google Cloud Storage using stream_context_create with the acl option, instead of simply move_uploaded_file. Is there a better way?Nathan

4 Answers

6
votes

Got this to work using file_put_contents with a stream.

$file = $_FILES['myfile']
$storeAt = 'gs://bucketname/filename.jpg

Old code

$saved = move_uploaded_file($file['tmp_name'],$storeAt);

New code, sets permissions and mime type

$options = array('gs'=>array('acl'=>'public-read','Content-Type' => $file['type']));
$ctx = stream_context_create($options);
$saved = file_put_contents($storeAt, file_get_contents($file['tmp_name']), 0, $ctx);

Go me!

1
votes

As of September 23 2014, I managed to upload files to Google Storage Cloud via appEngine and set the acl to public-read (everyone) like this:

form.php:

<?
require_once 'google/appengine/api/cloud_storage/CloudStorageTools.php';
use google\appengine\api\cloud_storage\CloudStorageTools;
$options = [ 'gs_bucket_name' => 'yourbucketname' ];
$upload_url = CloudStorageTools::createUploadUrl('/upload_handler.php', $options);

?>
<form action="<?php echo $upload_url?>" enctype="multipart/form-data" method="post">
    Files to upload: <br>
   <input type="file" name="userfile" size="40">
   <input type="submit" value="Send">
</form>    

upload_handler.php:

<?php
require_once 'google/appengine/api/cloud_storage/CloudStorageTools.php';
use google\appengine\api\cloud_storage\CloudStorageTools;

$fileName = 'gs://yourbucket/'.$_FILES['userfile']['name'];
echo $fileName."<br>";

$options = array('gs'=>array('acl'=>'public-read','Content-Type' => $_FILES['userfile']['type']));
$ctx = stream_context_create($options);

if (false == rename($_FILES['userfile']['tmp_name'], $fileName, $ctx)) {
  die('Could not rename.');
}

$object_public_url = CloudStorageTools::getPublicUrl($fileName, true);
echo $objectPublicUrl."<br>";
//header('Location:' .$objectPublicUrl); // redirects the user to the public uploaded file, comment any previous output (echo's).
?>

To be able to accept big files, I've also created a custom php.ini on the base directory of my app:

php.ini:

; This is a simple php.ini file on App Engine
; It enables output buffering for all requests by overriding the
; default setting of the PHP interpreter.
output_buffering = "On"
max_file_uploads = 0
upload_max_filesize = 100M
session.gc_maxlifetime = 10000

app.yaml, sets all images files as static and .php's as runnable, it looks like this:

application: myapp
version: 1
runtime: php
api_version: 1
threadsafe: true

handlers:
# Serve images as static resources.
- url: /(.+\.(gif|png|jpg))$
  static_files: \1
  upload: .+\.(gif|png|jpg)$
  application_readable: true

# Serve php scripts.
- url: /(.+\.php)$
  script: \1

Hope it helps anyone else ;)

0
votes

the option max_file_uploads can't be 0.

max_file_uploads = 10 (or whatever you want)

0
votes

None of the options listed here seem to work anymore.

The only way I've been able to get public access for files it to create a bucket with public access and use that for uploaded files.

gsutil defacl set public-read gs://bucket