将 PHP getimagesize 和 imagecreate 与 Google App Engine 和 Google Cloud Storage 结合使用

Using PHP getimagesize and imagecreate with Google App Engine and Google Cloud Storage

我想在GAE中使用PHP上传文件图片文件。

在存储之前,我想将每个文件转换为 JPEG 并将其降低为缩略图质量。

使用以下代码(在正常 PHP 环境中完全有效,减去特定于存储桶的调整),我能够接收上传并确定临时文件名和位置,但 getimagesize 生成尝试访问 CloudStorage 时出错。

$bucket = CloudStorageTools::getDefaultGoogleStorageBucketName();
$bucketPath = "gs://" . $bucket . "/" . $_SERVER["REQUEST_ID_HASH"] . "/";
$counter = 0;

foreach($_FILES["file"]["name"] as $idx => $tempFile) {
    $counter++;
    $sourceFile = $bucketPath . $tempFile;

    syslog(LOG_DEBUG, $sourceFile);

    $photoInfo = getimagesize($sourceFile);
    if ($photoInfo["mime"] == "image/jpeg") {
        $photoImage = imagecreatefromjpeg($sourceFile);
        $valid = true;
    }
    elseif ($photoInfo["mime"] == "image/gif") {
        $photoImage = imagecreatefromgif($sourceFile);
        $valid = true;
    }
    elseif ($photoInfo["mime"] == "image/png") {
        $photoImage = imagecreatefrompng($sourceFile);
        $valid = true;
    }

    if (isset($valid)) {
        $date = date("Y-m-d H:i:s");

        $photoFolder = rtrim($photoFolder, "/") . "/";
        $photoFile = "Test {$counter} {$date}.jpg";

        $imageSaved = imagejpeg($photoImage, $photoFolder.$photoFile, 50);

        syslog(LOG_DEBUG, "File saved is " . $imageSaved);
    }
}

第一个系统日志条目确认文件路径和名称...

gs://[myappid].appspot.com/AC3E3530/IMG_20160701_120144.jpg

错误日志显示尝试打开流时出错,但我不知道如何解决。

PHP Warning:  getimagesize(gs://[myappid].appspot.com/AC3E3530/IMG_20160701_120144.jpg): failed to open stream: "\google\appengine\ext\cloud_storage_streams\CloudStorageStreamWrapper::stream_open" call failed in /base/data/home/apps/s~[myappid]/v1.394746390020376247/code/server.php on line 169

我已经在 GAE 上使用此功能的变体,使用我的服务器通过 Twilio 接收的照片(其中 processPhoto() 是与我上面摘录的代码相同的函数)。在这种情况下,我将 getimagesize 和 imagecreate 与 URL 一起使用。我只是不知道如何用 CloudStorage 做同样的事情。

if ($fetch && $numMedia > 0) {
    for ($x = 0; $x < $numMedia; $x++) {
        $sourceFile = $_REQUEST["MediaUrl" . $x];
        $sid = $_REQUEST["MessageSid"];
        processPhoto("sms", $projectID, $sourceFile, $caption, $sid, $mobile, $message);
    }
}

我猜您遇到了 limitation of the Standard Environment,其中标准运行时中的 getimagesize 本机函数不适用于 gs:// URL 等文件扩展名。

我认为问题在于临时文件在我可以处理之前被删除了。所以,我...

  1. 删除了处理多个文件的功能(我 无论如何都不需要)。
  2. 立即将文件移动到另一个存储桶。
  3. 检查文件的类型。
  4. 根据需要保存。
  5. 删除临时文件。

这是我在 PHP 中生成的表格。没有提交按钮,因为我用 jQuery.

观察文件更改
<form id='form_uploadPhotos' method='post' enctype='multipart/form-data' action='{$websiteURL}?action=uploadPhotos'>
    <input type='file' id='input_uploadPhoto' name='file'>
    <input type='hidden' name='projectID' value='{$projectID}'>
</form>

这是提交表单时调用的 uploadPhotos 函数:

if ($action == "uploadPhotos") {
    $projectID = preg_replace("/\D/", "", $_REQUEST["projectID"]);

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

    $date = date("Y-m-d H:i:s");
    $time = time();

    $photoFile = sprintf("%08d", $projectID) . "." . $date . "." . $time . ".TEMP";
    $sourceFile = $photoFolder.$photoFile; // The default photo folder is defined elsewhere.

    move_uploaded_file($_FILES["file"]["tmp_name"], $sourceFile);
    processPhoto("upload", $projectID, $sourceFile, null, null, null, null);
}

这是处理照片的函数。它由也接收照片的其他进程调用(例如,通过 Twilio 的 SMS 附件)。

function processPhoto($via, $projectID, $sourceFile, $caption, $twilioMessageID, $smsMobile, $smsMessage) {
    global $photoFolder;

    $photoInfo = getimagesize($sourceFile);
    if ($photoInfo["mime"] == "image/jpeg") {
        $photoImage = imagecreatefromjpeg($sourceFile);
        $valid = true;
    }
    elseif ($photoInfo["mime"] == "image/gif") {
        $photoImage = imagecreatefromgif($sourceFile);
        $valid = true;
    }
    elseif ($photoInfo["mime"] == "image/png") {
        $photoImage = imagecreatefrompng($sourceFile);
        $valid = true;
    }

    if (isset($valid)) {
        $date = date("Y-m-d H:i:s");
        $time = time();
        $photoFile = sprintf("%08d", $projectID) . "." . $date . "." . $time . ".JPEG";

        $photoImage = imagecreatefromjpeg($sourceFile);
        list($width, $height) = getimagesize($sourceFile);
        if (max($width, $height) > 800) {
            $scale = 800/max($width, $height);
            $newWidth = floor($width * $scale);
            $newHeight = floor($height * $scale);
            $saveImage = imagecreatetruecolor($newWidth, $newHeight);
            imagecopyresampled($saveImage, $photoImage, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
        }

        $imageSaved = imagejpeg($photoImage, $photoFolder.$photoFile);
        imagedestroy($photoImage);

        if ($imageSaved) {
            if (isset($twilioMessageID)) {
                $twilioMediaID = substr($sourceFile, strrpos($sourceFile, "/") + 1);
                purgeTwilioMedia($twilioMessageID, $twilioMediaID);
            }
            elseif (substr($sourceFile, strrpos($sourceFile, ".")) == ".TEMP") {
                unlink($sourceFile);
            }

            <Additional processing (e.g., adding entry to database.)
            .
            .
            .
        }
    }
}

注:"list($width, $height..."和"imagecopyresampled..."之间的图像缩放代码是根据Dano's answer另一个问题