Direct File Uploads for PHP 5.5

One of the new features we announced in the 1.9.18 App Engine release is the ability to upload files directly to you application, without the need to upload the files to Google Cloud Storage first.

Direct uploads leverages the same in memory virtual filesystem that is used to provide temporary filesystem support. Direct uploads are only available with the PHP 5.5 runtime and are also limited to a maximum combined size of 32MB, which is the incoming request size limit.

Direct Upload Example

Following is a small sample application that demonstrates direct file uploads. This sample application:

  • Uses HTML5 multiple file upload support to upload image files.
  • Saves the original uploaded file into Google Cloud Storage.
  • Creates a greyscale version of the uploaded image and writes that to Google Cloud Storage.
  • Uses the image serving API to create links to serve the stored images at original size.
  • Also uses the image serving API to create thumbnail links of the images, without the application having to create the thumbnails.
  • Finally, displays a simple page with the thunbnailed links to the saved files.

For this application we’ll create 3 source files.

app.yaml

The app.yaml file has the following contents. Note that the runtime is php55.

application: php-uploads
version: 1
runtime: php55
api_version: 1
threadsafe: true

handlers:
- url: /handle_upload
  script: handle_upload.php

- url: .*
  script: direct_upload.php

direct_upload.php

This file presents a form for the user to upload multiple files to your application. As direct uploads are only in PHP 55 it checks that as well.

<?php
// Direct uploads requires PHP 5.5 on App Engine.
if (strncmp("5.5", phpversion(), strlen("5.5")) != 0) {
  die("Direct uploads require the PHP 5.5 runtime. Your runtime: " . phpversion());
}
?>
<html>
<body>
<form action="handle_upload" method="post" enctype="multipart/form-data">
  Send these files:<p/>
  <input name="userfile[]" type="file" multiple="multiple"/><p/>
  <input type="submit" value="Send files" />
</form>
</body>
</html>

handle_upload.php

The handle_upload script does the heavy lifting of creating the greyscale images, saving them in Cloud Storage and displaying the results. If you were doing this in a production app you’d need a lot more error handling, but I’ve left it out for brevity.

<?php

use google\appengine\api\cloud_storage\CloudStorageTools;

$bucket = CloudStorageTools::getDefaultGoogleStorageBucketName();
$root_path = 'gs://' . $bucket . '/' . $_SERVER["REQUEST_ID_HASH"] . '/';

$public_urls = [];
foreach($_FILES['userfile']['name'] as $idx => $name) {
  if ($_FILES['userfile']['type'][$idx] === 'image/jpeg') {
    $im = imagecreatefromjpeg($_FILES['userfile']['tmp_name'][$idx]);
    imagefilter($im, IMG_FILTER_GRAYSCALE);
    $grayscale = $root_path .  'gray/' . $name;
    imagejpeg($im, $grayscale);

    $original = $root_path . 'original/' . $name;
    move_uploaded_file($_FILES['userfile']['tmp_name'][$idx], $original);

    $public_urls[] = [
        'name' => $name,
        'original' => CloudStorageTools::getImageServingUrl($original),
        'original_thumb' => CloudStorageTools::getImageServingUrl($original, ['size' => 75]),
        'grayscale' => CloudStorageTools::getImageServingUrl($grayscale),
        'grayscale_thumb' => CloudStorageTools::getImageServingUrl($grayscale, ['size' => 75]),
    ];
  } 
}

?>
<html>
<body>
<?php
foreach($public_urls as $urls) {
  echo '<a href="' . $urls['original'] .'"><IMG src="' . $urls['original_thumb'] .'"></a> ';
  echo '<a href="' . $urls['grayscale'] .'"><IMG src="' . $urls['grayscale_thumb'] .'"></a>';
  echo '<p>';
}
?>
<p>
<a href="/">Upload More</a>
</body>
</html>

If you stumble across any problems, please let us know on either stack overflow or by creating an issue in our tracker.

2 thoughts on “Direct File Uploads for PHP 5.5

  1. David

    I’ve been trying to use this new feature, and have followed the above steps as closely as possible, but I have not been able to upload larger files (say 16MB – the entire request is easily under 32MB as mentioned)

    The error in Google Cloud Console: While handling this request, the process that handled this request was found to be using too much memory and was terminated. This is likely to cause a new process to be used for the next request to your application. If you see this message frequently, you may have a memory leak in your application.

    Are there any settings that need to be adjusted to being able to upload larger files?
    I have tried:
    yaml: instance_class: F4_1G
    php.ini: memory_limit = 1024M; upload_max_filesize = 30M; post_max_size = 30M

    1. slangley Post author

      Sorry for the delayed response.

      As long as the total request is < 32 MB I can’t see a reason for the application to exceed memory limits even on an F1. Can you file a bug in the issue tracker and if possible attach a small repro?

Comments are closed.