ローカルの開発環境でGoogle Cloud Storageのエミュレート

1,497 views
Skip to first unread message

ke...@akakabulab.jp

unread,
Aug 4, 2014, 6:24:34 AM8/4/14
to google-app-...@googlegroups.com
初めて投稿します。よろしくお願いします。
ローカルの開発環境でGoogle Cloud StorageをエミュレートするSDKは無いでしょうか。

当方はGAE for PHP上でGCLを使うアプリを作ろうとしています。
プログラムは、本番環境にデプロイすれば動くものの、ローカルでは動かないため、本番環境でデバッグしています。
当方のサービスにアクセスが少ないのを良い事に、デバッグの間サービスを中断していますが、いつまでそれで行けるかと恐れています。

najeira

unread,
Aug 5, 2014, 9:43:33 PM8/5/14
to google-app-...@googlegroups.com
najeiraです。

GCS APIのラッパーを作って、ローカルと本番で動作を変えるようにするか、
開発用に別のバケットを用意して、開発中はローカルからそのバケットを使うようにしてはどうでしょうか。

ke...@akakabulab.jp

unread,
Aug 11, 2014, 9:16:01 PM8/11/14
to google-app-...@googlegroups.com
お返事ありがとうございます。
やっぱりGCSのエミュレーターは無いのですね。自分の探し方が悪いのかと思っていました。

現在、開発はGCSが焦点になっていますので、GCSの部分をスルーするような変更では開発になりません。また、ローカルの開発環境のうちGCSの部分だけを(gsutilを使って?)Googleの本物のGCSで動作させるように環境を作るのも難しいです。
なぜなら、GAE for PHPではブラウザからHTTPのPOSTでデータを送ると、PHPに処理が移ってきたときには既にGCSに格納された状態であり、それをローカルで再現するにはApacheか何かを変更しないとなりません。そして、Googleのサーバーはドキュメントに無い動作をしているので(*1)、差異を見つけて再現するのも大変な手間です。

そう言う事を考えると、開発専用のアプリをGoogleに登録して非公開で使用すれば、本来のサービスを中断しなくて済む確実な方法かな、と思います。(もちろんお金が余計にかかります)

*1 Googleのサーバーがドキュメントに無い動作をする件はまた別途質問します。

najeira

unread,
Aug 12, 2014, 8:57:02 PM8/12/14
to google-app-...@googlegroups.com
najeiraです。


「ローカルでGCSが動かない」というのは、
ローカルだと上記のドキュメントにあるような
コードが動かないということでしょうか?

どう動かないのでしょうか。
どういうエラーが出ていますか?

ke...@akakabulab.jp

unread,
Aug 12, 2014, 10:25:26 PM8/12/14
to google-app-...@googlegroups.com
お返事ありがとうございます。

ローカルの環境では、PHPに処理が移ってきた時点で、アップロードしたファイルのサイズが異常になっています。実質、アップロードできていないようです。

背景と詳細を説明します。
通常のGCSの利用では、自分のプログラムから能動的にファイルの読み書きをすると思いますが、今回、私が利用している方法はちょっと違います。
やり方は下のURLに説明があります。
この方法では、ユーザーがHTTPのPOSTで送ってきたデータがGoogleのサーバーによって自動的にGCS内に保存されます。
自分のプログラムに処理が移ってきたときには、PHPのグローバル変数$_FILES に、アップロード先のパス等必要な情報が入って渡されます。(これはPHPの通常の動作)
そして私のローカル環境では、HTTPのPOSTに対してステータスコード201が返るのに、PHPに処理が移ってきたときにはファイルサイズが異常になっている等、実質的にアップロードできていないようです。

$_FILESの内容
$_FILES array(1) { 
 ["d4p_attachment"]=> array(5) {
  ["name"]=> array(1) {
   [0]=> string(7) "poo.jpg"
  }
  ["type"]=> array(1) {
   [0]=> string(21) "message/external-body"
  }
  ["tmp_name"]=> array(1) {
   [0]=> string(26) "/private/var/tmp/phpde8eKk"
  }
  ["error"]=> array(1) {
   [0]=> int(0)
  }
  ["size"]=> array(1) {
   [0]=> int(332)    ←本当は26kくらいのはず
  }
 }
}

najeira

unread,
Aug 13, 2014, 9:25:14 PM8/13/14
to google-app-...@googlegroups.com
najeiraです。

CloudStorageTools::createUploadUrl() を使っているということですね。

このメソッドを使ったとき、ローカルの場合はおそらく、
そのマシンのファイルに保存するようになっていると思います。
ローカルの場合、formのactionの値はGCSにはなっていないと思います。

>  ["tmp_name"]=> array(1) {
>   [0]=> string(26) "/private/var/tmp/phpde8eKk"
>  }

ここでファイル名が出ているので、これが保存されたファイルのようですね。

このファイルの中身はどのようなものでしょうか?
もしかしたらヒントになるかもしれません。

ke...@akakabulab.jp

unread,
Aug 14, 2014, 3:24:09 AM8/14/14
to google-app-...@googlegroups.com
お返事ありがとうございます。
アップロードしたのがJPEGファイルなので、ファイルの先頭付近に"JFIF"の文字があるはずですが、そう言ったものは見つかりませんでした。
ただ、調べたのは随分前で、先日またGAEのSDKがバージョンアップしたようなので、新しいものでまた調べて見ます。

ke...@akakabulab.jp

unread,
Aug 18, 2014, 9:55:56 AM8/18/14
to google-app-...@googlegroups.com

2014年8月14日木曜日 16時24分09秒 UTC+9 ke...@akakabulab.jp:
ただ、調べたのは随分前で、先日またGAEのSDKがバージョンアップしたようなので、新しいものでまた調べて見ます。

最新のGAE SDK 1.9.9で試しました。
(ちなみにGAE for PHPでWordpressを使うにはGAE for Wordpressという物も要りますが、こちらは3月からバージョンアップが無く、1.4のままです。)

結果は同じでした。$_FiLESの中身も基本的に一緒です。
今回は、アップロードで一時的に保存されるファイル(後述$_FiLESの /private/var/tmp/phpQX9K8n)を見てみたら、テキストファイルでした。

一時ファイルの内容。
-------------------------------
Content-Type: image/jpeg
Content-Length: 26205
Content-MD5: NDgwMWJkMGM1MzVkODAzYTIxNjA2MDAzYTRiMDUzMDk=
X-AppEngine-Cloud-Storage-Object: /gs/akakabu-bbs-gae-files/upload//fake-aBaP6jfOoUGMTxK8KEL0eg==
content-disposition: form-data; name="d4p_attachment[]"; filename="poo.jpg"
X-AppEngine-Upload-Creation: 2014-08-18 13:25:16.890850
-------------------------------

$_FiLESの内容
(
    [d4p_attachment] => Array
        (
            [name] => Array
                (
                    [0] => poo.jpg
                )

            [type] => Array
                (
                    [0] => message/external-body
                )

            [tmp_name] => Array
                (
                    [0] => /private/var/tmp/phpQX9K8n
                )

            [error] => Array
                (
                    [0] => 0
                )

            [size] => Array
                (
                    [0] => 343
                )

        )
)

najeira

unread,
Aug 18, 2014, 8:57:41 PM8/18/14
to google-app-...@googlegroups.com
najeiraです。

一時ファイル内に記載のある

> /gs/akakabu-bbs-gae-files/upload//fake-aBaP6jfOoUGMTxK8KEL0eg==

これが実際のファイル名っぽいですね……。

fopenなどで `gs://akakabu...` とすると画像ファイルが読めるかもしれません。


2014年8月18日月曜日 22時55分56秒 UTC+9 ke...@akakabulab.jp:

ke...@akakabulab.jp

unread,
Aug 19, 2014, 1:10:57 AM8/19/14
to google-app-...@googlegroups.com
たびたびありがとうございます。

2014年8月19日火曜日 9時57分41秒 UTC+9 najeira:
> /gs/akakabu-bbs-gae-files/upload//fake-aBaP6jfOoUGMTxK8KEL0eg==

これが実際のファイル名っぽいですね……。


しかし、/gs/... のファイルが見つからないのです。
  sudo find / -name akakabu-bbs-gae-files
でなにも出ないので、お手上げです。

ところで本番環境での$_FILESも見てみました。
ローカルの開発環境とは明らかに違い、アップロードしたファイルの本体が $_FILES に書かれています。
ローカル環境で/gs/... のファイルが見つかるようなら、ローカルでだけ$_FILESの中身を書き換えるように処理を追加して対応出来たでしょうに。

本番環境の$_FILES
(
 [d4p_attachment] => Array
  (
   [name] => Array
    (
     [0] => test.jpg
    )
   [type] => Array
    (
     [0] => image/jpeg
    )
   [tmp_name] => Array
    (
     [0] => gs://akakabu-bbs-gae-files/upload/L2FwcGhvc3RpbmdfcHJvZC9ibG9icy9BRW5CMlVyZEY3djNkSm5DOHhTZGNQLU9BWWE5QWt2eERZckx3QWF1bU5seDVsUGtQY1VyYnpBalQ5MEtWTGNfMTNSQTRZMUllZkpMalZramlKam03M09KcFhBS1ozNk5iQS5jYjVXZGV0ZTFkWGV2ZXpr
    )
   [error] => Array
    (
     [0] => 0
    )
   [size] => Array
    (
     [0] => 92251
    )
  )
)

ke...@akakabulab.jp

unread,
Aug 20, 2014, 9:16:19 AM8/20/14
to google-app-...@googlegroups.com
2014年8月19日火曜日 14時10分57秒 UTC+9 ke...@akakabulab.jp:
2014年8月19日火曜日 9時57分41秒 UTC+9 najeira:
> /gs/akakabu-bbs-gae-files/upload//fake-aBaP6jfOoUGMTxK8KEL0eg==

これが実際のファイル名っぽいですね……。


しかし、/gs/... のファイルが見つからないのです。
 
追試です。
開発マシンのルートディレクトリにも、Apacheのドキュメントルートにも、"gs"などというデイレクトリが無いのは承知の上で、
もしかしたらGAEのSDKがとんでもない所にあるディレクトリにリンクさせていたり、ファイルをアップロードした後のごく短い時間だけパスが存在するのかもしれないと考え、PHPのプログラム中に検証コードを入れてみてみました。
結果はやっぱりパスは存在しませんでした。

検証コードの動作概略
(1) $_FILESが空でない時だけ以下の処理をする。
(2) ファイル名 $_FILES["d4p_attachment"]["tmp_name"][0] のファイルを読み込む。
  $_FILES["d4p_attachment"]["tmp_name"][0] の中身は例えば "/private/var/tmp/phpsZ40oG"だった。
(3) 読み込んだファイルの3行目(先頭行は0)から文字列を切り出す。
 切り出した結果は例えば "/gs/akakabu-bbs-gae-files/upload//fake-NwrCHmRjBzU54-TnqVYQOg=="だった。
(4) (3)の文字列をファイル名として、fopen(またはfile)してみる。

(4)の結果の戻り値は常にfalseでした。

kenta wataru

unread,
Aug 20, 2014, 12:04:25 PM8/20/14
to google-app-...@googlegroups.com
こんにちは。

Mac OS X Marverics/Appengine PHP SDK 1.9.9を
インストールしたもので、単純なphpでアップロードフォームを書いて
試してみましたけど、これは特に問題なかったですね。
※フォームとupload_handlerはphpファイルを分けて書き、app.yamlに
パスを追加した単純なものです。

開発環境であっても、$_FILES['name']['tmp_name']に入ってくるパスが
gs://で始まるパスだったので、いわゆるfopen wrapper経由のアクセスに
なるパスなのを確認してます。
※実ファイルはMac上では$TMPDIR/appengine.[appname].[username]/blobs
配下にどうやら格納されるようですが。

Wordpressを移植されようとしてるんでしょうか?
環境依存か、こちらの問題ではないかなと感じました。
Wordpressの内部的なことに関してはアドバイスは出来ませんが・・・
勘で言えば、ルーティング中に$_FILESの中身を弄られたりしてるのでは?


2014年8月20日 22:16 <ke...@akakabulab.jp>:
> --
> このメールは Google グループのグループ「Google-App-Engine-Japan」に登録しているユーザーに送られています。
> このグループから退会し、グループからのメールの配信を停止するには
> google-app-engine...@googlegroups.com にメールを送信してください。
> このグループに投稿するには google-app-...@googlegroups.com にメールを送信してください。
> http://groups.google.com/group/google-app-engine-japan からこのグループにアクセスしてください。
> その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。

najeira

unread,
Aug 20, 2014, 8:54:39 PM8/20/14
to google-app-...@googlegroups.com
najeiraです。

"/gs/..." ではなく "gs://..." にしてもfopenできませんか?
(それとupload後のスラッシュを1つにしてみる)

あと、アップロードしている側の form で、enctype は何にしていますか?

ke...@akakabulab.jp

unread,
Aug 21, 2014, 5:46:03 AM8/21/14
to google-app-...@googlegroups.com
こんにちは、WdWeaverさん。

> Mac OS X Marverics/Appengine PHP SDK 1.9.9を
> インストールしたもので、単純なphpでアップロードフォームを書いて
> 試してみましたけど、これは特に問題なかったですね。

わざわざ実験してしてくださってありがとうございます。
うちはMac OSX Liom ですので、近いですね。
実験は CloudStorageTools::createUploadUrl()  を使ったものでしょうか。
もしそうなら確かに、私のところでだけ動いてないということで、大変参考になります。
(詳細は以下を参照。

開発環境であっても、$_FILES['name']['tmp_name']に入ってくるパスが
> gs://で始まるパスだったので、

これも大変参考になりす。
この差がどこから来ているのかがポイントのようですね。

> ※実ファイルはMac上では$TMPDIR/appengine.[appname].[username]/blobs 
> 配下にどうやら格納されるようですが。 

うちでも確かにそのようなディレクトリが出来て、さらにその下、何階層か下った所にアップロードしたファイルと同じ物ができました。

> Wordpressを移植されようとしてるんでしょうか?

いえ、Wordpress自体はGoogleが公式に対応しています。
GAE for Wordpress 1.4というプラグインを入れるのが条件です。
うちではそれに加えて、WordpressのプラグインとしてbbPress(Wordpressを掲示板化)とGD bbPress Attachments(bbPressの投稿に画像添付を可能にする)の2つを入れていて、ここの部分はGoogleの想定から外れるところです。
bbPressまでは何もいじらなくて動いたのですが、2つめのプラグインAttachmentsでは添付ファイルのアップロード先をGCSに変更する必要があり、前述の CloudStorageTools::createUploadUrl() の処理を加えるソースコードの修正をしています。これで本番環境では動いています
それ以外はソースコードの変更は無いのですが。

ke...@akakabulab.jp

unread,
Aug 21, 2014, 5:58:34 AM8/21/14
to google-app-...@googlegroups.com
こんにちは、najeira さん。


> "/gs/..." ではなく "gs://..." にしてもfopenできませんか?

WdWeaverさんの指摘にあるように、開発環境でも本来はアップロードしたファイル本体の名前が$_FILESに入っているはずなので、開発環境特有の処理を加える方向の追求は打ち切りたいと思います。
助言ありがとうございました。

kenta wataru

unread,
Aug 21, 2014, 6:29:51 AM8/21/14
to google-app-...@googlegroups.com
こんにちわ。

>実験は CloudStorageTools::createUploadUrl() を使ったものでしょうか。
>もしそうなら確かに、私のところでだけ動いてないということで、大変参考になり

はい、そうです。

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

の$uをformのactionに入れてるだけです。
これは/_ah/upload/で始まるURLに飛び、アップロードされた後に
ハンドラに指定したphpソースが実行されているという状態になりますが、
このハンドラで$_FILESをvar_dumpした限り、先のメールの記載通りの
状況となっています。

>GAE for Wordpress 1.4というプラグインを入れるのが条件です。
さらっと見てみたら、このプラグインは内部的に開発環境か本番環境かを
判断するロジックなども入っているようなので、そのあたりが悪さを
している可能性はありますね。



2014年8月21日 18:46 <ke...@akakabulab.jp>:

ke...@akakabulab.jp

unread,
Aug 22, 2014, 6:39:16 AM8/22/14
to google-app-...@googlegroups.com

2014年8月21日木曜日 19時29分51秒 UTC+9 WdWeaver:

>GAE for Wordpress 1.4というプラグインを入れるのが条件です。
さらっと見てみたら、このプラグインは内部的に開発環境か本番環境かを
判断するロジックなども入っているようなので、そのあたりが悪さを
している可能性はありますね。


上記を参考に$_FILESの中身を変えている部分を探しましたが、また行き詰まりました。

Google作成部分(GAE for Wordpressと GAE SDK )を中心に探した所、GAE for Wordpress内にuploads.phpというファイルを見つけました。
コード内のコメントに以下のようにありますし、
------------------------------------------
 * Hijacks the uploading functionality in WordPress to use Google Cloud Storage
 * for the media library.
------------------------------------------
POSTの後でこの中を通過する事がログで分かります。
しかしこの uploads.php に来た時点で既に$_FILESの中身は画像データでなくなっています。
これより上流を探さないとならないのですが、 uploads.php を呼び出しているファイルがありません。
(uploads.php は関数などを定義せず、処理が裸で書いてあり、grep で"uploads.php"を探しても何も出ない)

どうも GAE SDK内のバイナリファイルから呼んでいるのではないか、$_FILESの中身を変えているのもバイナリファイルではないか、という気がします。そのため、これ以上の追跡は無理のようです。
どうも長い間、おつきあいくださりありがとうございます。

kenta wataru

unread,
Aug 23, 2014, 12:18:09 PM8/23/14
to google-app-...@googlegroups.com
こんにちは。

こちら、追跡を諦められたようですが、個人的に興味があったので
状況を追って見ました。

多分元凶としてはこれなんじゃないかなと思います。
https://code.google.com/p/googleappengine/issues/detail?id=10763

私も引き続き追う為にMac上でxdebugを使えるようにしようと考えて、
brewで構築したインタープリタに入れ替えたところ、kenjiさんと
同じ現象(tmp_nameが/varから始まる)に至りましたので、
xdebugの利用の為にphpインタープリターの入替をされているんじゃ
ないかと推測しますがいかがでしょうか。

SDKに同梱されているphpインタープリタには、こちらの
https://github.com/GoogleCloudPlatform/appengine-php
のようで、かなり手が入っていると思われます。
※SDK1.9.9には5.4.30が入っているのに、こちらは5.4.19と古いのが気になりますが。

$_FILESにgs://と入るのも、PHPのソース、main/rfc1867.cにオリジナルから
手が入っているためのようです。Linux他環境用となっているSDKにはPHPが同梱
されてないので、github上のソースをなんとかコンパイルしてインストールしない限り、
同じ状況になるのではと思います。
※僕はこのソースのMac上でのコンパイルは依存関係とコンパイルエラーに翻弄されたので諦めました・・・

Windows版であればissueのコメントにあるようにxdebugも同梱?のようなので
こだわりがなければそちらを試してみてはいかがでしょうか。


2014年8月22日 19:39 <ke...@akakabulab.jp>:

ke...@akakabulab.jp

unread,
Aug 24, 2014, 1:13:28 AM8/24/14
to google-app-...@googlegroups.com
2014年8月24日日曜日 1時18分09秒 UTC+9 WdWeaver:

SDKに同梱されているphpインタープリタには、こちらの
https://github.com/GoogleCloudPlatform/appengine-php
のようで、かなり手が入っていると思われます。
 
なんとGAE SDK専用PHPインタープリターがあったのですか。恥ずかしながら知りませんでした。
自分が環境を構築した時のドキュメントにはそういうことは書いてありませんでした。(最新のドキュメントにも無いような)
GAE SDKのディレクトリ(GoogleAppEngineLauncher)を探してみると確かにphp-cgiがあり、それを使ったらあっさり画像添付が出来てしまいました。

大変お騒がせしました。
Reply all
Reply to author
Forward
0 new messages