Использование PHP getimagesize и imagecreate с Google App Engine и Google Cloud Storage

Я хочу использовать PHP в GAE для загрузки файлов изображений.

Перед сохранением я хочу преобразовать каждый файл в 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);
    }
}

person Alan M.    schedule 07.08.2016    source источник


Ответы (2)


Я думаю, проблема была в том, что временный файл был удален до того, как я смог его обработать. Так что я...

  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);
}

Это функция, которая обрабатывает фото. Его вызывают другие процессы, которые также получают фотографии (например, вложения SMS через Twilio).

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 ответ на другой вопрос.

person Alan M.    schedule 08.08.2016

Я предполагаю, что вы сталкиваетесь с ограничением стандартной среды. где собственная функция getimagesize в стандартной среде выполнения не работает с расширениями файлов, такими как gs:// URL-адреса.

person E. Anderson    schedule 07.08.2016
comment
Спасибо за ваш ответ. Я изучил различия между сервисами и пришел к выводу, что недостаточно быстро получаю доступ к файлу. Итак, как подробно описано в моем ответе, теперь я перемещаю файл и работаю с ним в другом месте. - person Alan M.; 08.08.2016