You are here
Home > 未分類

掲載コードの実行

今まで、ちょびちょびコードを掲載してきましたが、実際にテストできるコードを全公開します。

私が使用しているバージョンコントロールは、git(ギット)です。gitと言えば、もちろんgithum.com(ギットハブ)が有名。しかし、彼らの無料アカウントはプライベートのプロジェクト数に制限があるために、私はユーザー数の制限がありプライベートのプロジェクト数の制限がないbitbucket.org(ビットバケット)を使用しています。また、ビットバケットは日本語版にもなります(まだベータ版ですが)。

まず、実行できるコードはこのリンクから、コード

lotsofbytes - larajapan code — Bitbucket 2015-10-07 15-34-25

英語画面は、言語のドロップダウンで日本語に変換できます。

lotsofbytes - larajapan code — Bitbucket 2015-10-07 15-34-57

完全な日本語翻訳とは言えないですが、十分。

ファイルのダウンロード

次は、以下をコマンドラインで実行してください。ウェブにアクセスできるディレクトリで。

git clone https://bitbucket.org/lotsofbytes/larajapan-code.git

実行したディレクトリの真下にlarajapan-codeのサブディレクトリが作成され、そこへレポジトリのファイルがダウンロードされます。このサブディレクトリは、好きな名前に改名して問題ありません。

しかし、そのダウンロードでは、masterのブランチとなっているので、前回のコードを設定するには、以下を実行。

git fetch && git checkout -b 2015-09-30

ディレクトリのパーミッションを変えます。storageはログやセッションやキャッシュなどが保存されるディレクトリです。

chmod -R 777 storage

次はコンポーザー(composer)が必要です。システムに存在しないなら、rootユーザーで以下を実行してインストールできます。


curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

その後、git checkoutをしたディレクトリで、以下を実行。

composer install

アプリの設定

さて、次は設定ファイルの編集です。まず、サンプルの設定ファイルをコピーして、この環境でのアプリの設定ファイルとします。

cp .env.example .env

このファイルで編集が必要なのは今のところ、以下のDB設定の部分です。

DB_HOST=localhost
DB_DATABASE=データベースの名前
DB_USERNAME=データベースユーザーの名前
DB_PASSWORD=データベースのパスワード

その後、以下を実行してくさい。

php artisan key:generate

それにより、.envのファイルの

APP_KEY=SomeRandomString

の「SomeRandomString」に値が「s0IWRnfPlNAiPl7Bwl1MX8V7i14loYyK」のような値に変更されます。この値は、アプリのすべての暗号化に使用されるので、一度設定したら2度と変えないように。

次は、前回で使用したDBテーブルの作成です。以下を実行すると、memberのテーブルがDBに作成されます。

php artisan migrate

さて、これで準備は完了です。

以下のようなURLにアクセスすると、会員登録画面が表示されます。localhostの部分は使用している環境により変わりますので、注意を。

http://localhost/larajapan-code/public/signup

メンテナンス画面の裏口

先日、開発完了のLaravelのプログラムをインストールするときに、私だけのためにメンテナンス画面に裏口があったらいいなと思いました。

Laravelでは、

php artisan down

このコマンドの実行で、すべてのアクセスを以下のようなメンテナンス画面にできます。そのモードに切り替えて、DBの変更とかなどのインストールの作業を誰にも邪魔されずにするのです。

Be right back. 2016-01-09 13-16-41

しかし、インストール後には、できる限りの動作テストを行いたいのですが、自分も含めて誰もアクセスできない状態は不都合です。せめて私や関係者だけ、つまりそれらのIPだけからは通常に見れるようにしたいのです。

私がフレームワークなしの時代に開発したプログラムでは、すべてのプログラムに共通で最初に読み込まれるPHPファイルに、以下のようなコードで、私だけが閲覧できるようにしていました。

$allow = array('xxx.xxx.xxx.xxx');

if (isset($_SERVER)) // ウェブのアクセスのみ
{
    if (isset($_SERVER["REMOTE_ADDR"]) && !in_array($_SERVER["REMOTE_ADDR"], $allow))
    {
        include_once "maintenance.php";
        exit;
    }
}

普段はこれらはコメントしておいて、メンテナンスのときにコメントを解除するのです。xxx.xxx.xxx.xxxは私の固定IPですが、そのIPだけが、メンテ画面を含むmaintenance.phpの実行をしないのです。

これと同じことをLaravelでできないでしょうか?

ちょっと調べたところ、以下のファイルにおいて、


class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * @var array
     */
    protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
    ];
...

vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php

このファイルがミドルウェアとして、メンテナンスのモードかどうかをチェックしているらしい。

ということで、そのファイルをコピーして、

app/Http/Middleware/CheckForMaintenanceMode.php

として、その中味を以下のように編集します。


namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Foundation\Application;
use Symfony\Component\HttpKernel\Exception\HttpException;

class CheckForMaintenanceMode
{
    /**
     * The application implementation.
     *
     * @var \Illuminate\Contracts\Foundation\Application
     */
    protected $app;
    protected $allow = ['xxx.xxx.xxx.xxx'];
    /**
     * Create a new middleware instance.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function __construct(Application $app)
    {
        $this->app = $app;
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {

        if ($this->app->isDownForMaintenance()) {
            if (!in_array($request->getClientIp(), $allow)) {
                throw new HttpException(503);
            }
        }

        return $next($request);
    }
}

基本的には、先のコードと同様なメカニズムです。

そして先のKernel.phpを

...
    protected $middleware = [
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
    ];
...

と編集する。簡単な変更ですが有用です。

ちなみに、メンテナンスの解除をするには、

php artisan up

これを実行するのみなのですが、ちょっとメカニズムに興味ありますね。

調べたところ、downでは、

storage/framework/down

という空のファイルを作成されます。そしてupの実行ではこのファイルが削除されます。意外とシンプルですね。

最後に、メンテナンスの画面は以下のファイルを編集します。

resources/views/errors/503.blade.php

publicのディレクトリを移動する

新規のLaravelのプロジェクトは、以下の実行で作成できます。

$ laravel new blog

/blogのディレクトリが作成され、そこには以下のようなディレクトリやファイルが作成されます。

app/
bootstrap/
config/
database/
public/
resources/
storage/
tests/
vendor/
artisan
composer.json
composer.lock
gulpfile.js
package.json
phpunit.xml
readme.md
server.php

/publicのディレクトリがウェブサイトのルートとなる仮定で、その他のディレクトリはユーザーからはアクセスできないという仮定なのですが、

しかし、現実は使用するサーバーの都合により、このpublicのディレクトリを違う場所に移動する必要があります。

例えば、

public

/usr/www/demo/webdocs

に、

その他のディレクトリやファイルは、ウェブがアクセスできない以下に

/usr/www/demo/blog

この変更に必要な設定は、Laravelではとても簡単です。

public/index.php、移動後では、/usr/www/demo/webdocs/index.phpを編集するだけです。

...
require __DIR__.'/../bootstrap/autoload.php';
...
$app = require_once __DIR__.'/../bootstrap/app.php';
..

...
require '/usr/www/demo/blog/bootstrap/autoload.php';
...
$app = '/usr/www/demo/blog/bootstrap/app.php';
..

と書き換えるだけです。

しかし、ここで1つ問題は、Laravel定義のpublic_path関数が返す値が、

/usr/www/demo/blog/public

となります。

これを修正するには、

...
require '/usr/www/demo/blog/bootstrap/autoload.php';
...
$app = '/usr/www/demo/blog/bootstrap/app.php';

$app->bind('path.public', function() {
    return __DIR__;
});
..

と、path.publicを設定する必要あります。
それにより、public_path関数が返す値は、

/usr/www/demo/blog/webdocs

となります。

Select2 セレクト複数選択

今回は人気のドロップダウンスクリプト、Select2を紹介します。

通常のドロップダウンリストは、

<div class="form-group{{ $errors->has('category') ? ' has-error' : '' }}">
    <label class="col-md-4 control-label">分類</label>

    <div class="col-md-6">
        {!! Form::select('category', ['犬', '猫', '猿'], null, ['class' => 'form-control']) !!}
    </div>
</div>

とテンプレートで指定すると、

select1

と表示。

これに、

<div class="form-group{{ $errors->has('category') ? ' has-error' : '' }}">
    <label class="col-md-4 control-label">分類</label>

    <div class="col-md-6">
        {!! Form::select('category[]', ['犬', '猫', '猿'], null, ['class' => 'form-control', 'multiple' => 'multiple']) !!}
    </div>
</div>

'multiple' => 'multiple'を追加すると、

multiple1

と複数選択に変わります。

しかし、この複数選択にSelect2を使用すれば、

multiple2

のように、ドロップダウンから複数選択して、最初の行に選択した値を表示してくれます。また、そこでXをクリックすることで削除もできます。

必要な設定は、

まず、

https://github.com/select2/select2/archive/master.zip

よりダウンロードして解凍してから、レイアウトのテンプレートを以下のように編集します。

...
<head>
...
<link href="{{ url('assets/css/select2/select2.min.css') }}" rel="stylesheet" type="text/css">
...
</head>
<body>
...

<script src="{{ url('assets/js/select2/select2.min.js') }}"></script>
<script src="{{ url('assets/js/select2/ja.js') }}"></script>

<script type="text/javascript">
      $(document).ready(function() {
          $(".js-multiple").select2({ width: 'resolve' });
      });
</script>
...

そして、画面のテンプレートを、

<div class="form-group{{ $errors->has('category') ? ' has-error' : '' }}">
    <label class="col-md-4 control-label">分類</label>

    <div class="col-md-6">
        {!! Form::select('category[]', ['犬', '猫', '猿'], null, ['class' => 'form-control js-multiple', 'multiple' => 'multiple']) !!}
    </div>
</div>

と編集します。

Select2には他にもいろいろな機能があります。

https://select2.github.io/examples.html

Debugbarで楽々デバッグ

以前に紹介した、Debugbar

私には、もうなくてはならないものになりました。対象の画面で実行されたDBのクエリーはすべて見ることができるし、セッションの中身の値も確認できる。

そして、もうひとつ、プログラムの中で自分が見たいという変数をdebug()のヘルパー関数で、以下のように使用すれば、


class UserController extends Controller
{
	public function getUpload()
	{
		return view('user/upload');
	}

	public function postUpload(Request $request)
	{
		debug($request->all());

		$file = $request->file('file');

		$filename = $file->getClientOriginalName();

		$request->file('file')->move(public_path('images'), $filename);
	}
}

以下の画面のように、バーで表示してくれます。

screen1

行をクリックすれば、詳細を表示します。

screen2

namespaceを指定してroutesすっきり

以前、マルチ認証の説明で以下のような、routes.phpを掲載しました(ユーザー認証(10)Laravel 5.2 マルチ認証)。

   Route::group(['middleware' => 'guest:users'], function()
    {
        Route::get('login', 'user\AuthController@getLogin');
        Route::post('login', 'user\AuthController@postLogin');
        Route::get('signup', 'user\SignupController@getSignup');
        Route::post('signup', 'user\SignupController@postSignup');
        Route::get('password/email', 'user\PasswordController@getEmail');
        Route::post('password/email', 'user\PasswordController@postEmail');
        Route::get('password/reset/{token}', 'user\PasswordController@getReset');
        Route::post('password/reset', 'user\PasswordController@postReset');
    });

ここ、user\AuthControllerとか、user\SignupControllerとか、namespaceのuser\がいつも繰り返されていて、面倒だなあと思いませんでしたか?

賢くなるものです。最近、ここnamespaceを使用して、user\を削除することが可能なこと見つけました。

   Route::group(['middleware' => 'guest:users', 'namespace' => 'user'], function()
    {
        Route::get('login', 'AuthController@getLogin');
        Route::post('login', 'AuthController@postLogin');
        Route::get('signup', 'SignupController@getSignup');
        Route::post('signup', 'SignupController@postSignup');
        Route::get('password/email', 'PasswordController@getEmail');
        Route::post('password/email', 'PasswordController@postEmail');
        Route::get('password/reset/{token}', 'PasswordController@getReset');
        Route::post('password/reset', 'PasswordController@postReset');
    });

すっきりしましたね。

また、php artisan route:listの実行でrouteをチェックしても、変更の前後ではまったく変わりません。

親子関係のテーブルでのクエリーの作成(クエリビルダー編)

いつもの例を使いますと、商品productと商品画像product_imageの親子関係、つまり、1対多の関係があるとして、これに対して検索画面を作成するとします。

検索画面では、商品名だけでなく、商品画像のMIMEも検索項目として、検索できるようにします。つまり、親のテーブルの項目(商品名)でなく、子のテーブルの項目(MIME)も指定可能とします。

この場合、すぐに思いつくのは、以下のようにjoinして、その検索結果を表示です。

//検索値
$input[] = [
    'name' => '商品名',
    'mime' => 'image/gif'
];

$products = DB::table('product')
    ->join('product_image', 'product.product_id', '=', 'product_image.product_id')
    ->where('product.name', $input['name'])
    ->where('product_image.mime', $input['mime'])
    ->get();

しかし、これでは検索結果の各行は、商品画像のレコードとなってしまいます。1商品に対して、複数のGIF画像があるときは、複数分商品が表示されます。今回は、該当する商品のみを表示したいです。

となると、


$products = DB::table('product')
    ->join('product_image', 'product.product_id', '=', 'product_image.product_id')
    ->where('product.name', $input['name'])
    ->where('product_image.mime', $input['mime'])
    ->groupBy('product.product_id')
    ->get();

あるいは、joinでなくwhereInを使用して、


$products = DB::table('product')
    ->where('product.name', $input['name'])
    ->whereIn('product.product_id', function($query) use($input) {
        $query->from('product_image')->select('product_id')->where('mime', $input['mime']);
    })
    ->get();

$query->tableでなく、$query->fromというところがちょいとややこしいですね。しかし、親のレコードだけを引き出すという点では、joinを使用するよりわかりやすいです。

実効すると、このSQL文は以下のようになります。

select * from `product` where `name` = '商品名' and `product`.`product_id` in (select `product_id` from `product_image` where `mime` = 'image/gif')

ちょっとしたパフォーマンスの改善

Laravelは非常にたくさんのファイルを起動時に読み込んでいるので、パフォーマンスの改善は以前から感心があります。最近、管理画面だけでrouteの数が300近いプログラムをインストールするにあたり、重たくなることを予想して、簡単にできる範囲でLaravelでのパフォーマンスの改善を調査してみました。

1.設定ファイルのキャッシュ作成

php artisan config:cache

この実行は、configのディレクトリにあるファイルすべてを合わせて1つのキャッシュファイルにします。これにより設定データのローディング時間を速めようということです。

ファイルは、

bootstrap/cache/config.php

として作成されます。

この使用において、注意は3点あります。

注意点1:プログラムにおいてenv()の関数を使用してはいけない

例えば、

.envのファイルにおいて、

APP_ENV=local

と設定していて、

$path = storage_path().'/'.env('APP_ENV').'/logs/test.log';

のように、現在の環境変数の値によりログファイルを置くディレクトリを変えるとすると、

$pathの値は、

/var/www/test/storage/local/logs/test.log

のようになります。

しかし、php artisan config:cacheを実行すると、env()の値は空となり、

/var/www/test/storage/logs/test.log

となってしまい、意図した場所とは違うことになってしまいます。

それゆえに、先のプログラムは以下と変更することが必要です。

$path = storage_path().'/'.config('app.env').'/logs/test.log';

もちろん、config/app.phpなどの設定ファイルの中でのenv()の使用は問題ないです。

注意点2:ダイナミックに値を設定しているconfigに気をつける

設定ファイルの値は、

config(['some_setting' => 'some_value']);

のようにダイナミックに値の設定が可能です。例えば、DBからの値をAppServiceProvider::boot()で読み込んでおいて、DBに再度アクセスすることなくプログラムのあちらこちらで使用しようというときなどに便利です。

ところが、php artisan config:cacheの実行時に、AppServiceProvider::boot()が実行されるので、それらの設定もキャッシュファイルに保存されてしまいます。これで、ダイナミックに変わる値が固定されては困ります。

しかし、ダイナミックに上書きされるので問題はなさそうです。しかし、プログラムの他の部分では問題があるかもしれません。使用には気をつけてください。

注意点3:.envやconfigのファイルを編集したら、必ずキャッシュを再作成

最後に忘れてはならないのは、.envconfig/*.phpのファイルを編集したら、必ずphp artisan config:cacheの実行が必要なことです。それなくしては、せっかくの変更も反映されません。

2.routeのキャッシュ作成

php artisan route:cache

こちらは、config:cacheと違い、この実行で作成されるファイル、

bootstrap/cache/routes.php

には、routes.phpファイルを読み込んでLaravelがマップしたデータ構造をbase64_encodeして、serializeした形で収めます。それゆえに、この読み込みとマップの作業を一気に短縮します。とくに、routeの数が大きいプロジェクトではパフォーマンスの改善に期待できる仕組みです。

それからconfig:cacheと同様に、routes.phpファイルを編集したら、必ずphp artisan route:cacheの実行が必要です。

3.共有クラスファイルの最適化

これは、環境変数のAPP_ENVがproductionの値のときにだけに有効なものです。また、設定ファイルに依存するので、設定ファイルをキャッシュするなら、php artisan config:cacheを実行してから以下を実行してください。

php artisan optimize

この実行で、共有されるクラスファイルを1つのファイルにまとめ、読み込み時間を短縮するのが目的です。以下のファイルを作成します。

bootstrap/cache/compiled.php

このファイルには、デフォルトでは、Laravel関連のファイルが含まれますが、必要なら以下の設定ファイルに追加が可能です。

bootstrap/cache/compile.php

改善した?

さて、実際にこれらの最適化でパフォーマンスはどれくらい変わるのでしょうか?

私の厳密ではないテストでは、DB操作を伴わない計測では10~30%の違いがありました。configよりもrouteやoptimizeの方が実際のパフォーマンスにより影響ありました。多分、設定ファイルが小さく数少ないためがその違いと思います。しかし、現実では、DBクエリーやCSS、JS、画像などのダウンロードがはるかに時間がかかるので、まだ私のプロジェクトのスケールではちょっとした改善というところです。スケールがより大きくなるとかなりの差となるかもしれません。

グローバル変数をダイナミックに管理

Laravelのバージョンが5になってから、グローバルスコープを持つ変数の設定は、.envconfig/のディレクトリの設定ファイルで、実用的しかも綺麗にまとまりました。変数の使用も、config('app.url')と、プログラムのでどこでも簡単に取得できます。

また、DBの設定などのデフォルト設定ファイル以外にも、独自の設定ファイルも作成できます。

例えば、

config/local.phpというファイルを作成して、


return [
        'convert' => '/usr/bin/convert', // 画像変換のプログラムのパス名
        'items_per_page' => 50,          // 1ページのアイテム数
        'max_upload_size' => 20,         // 最大アップロードの画像サイズ(MB)
        'company' => env('LOCAL_COMPANY', 'Lots of Bytes'), // 会社名
];

とすれば、config('local.company')と参照できます。

しかし、これらのグローバル変数設定の問題は、プログラムとして設定ファイルあるいは.envでハードコードしなければならないことです。

グローバル変数をDBに値を保存して、管理画面で以下のように値を編集できて、プログラムの各所で使用できるようにするには、どうしたらよいのでしょうか?

my-application

幸いにも、config()の関数は、取得だけでなく書き込みも可能なのです。


config(['global.admin_email' => 'abc@gmail.com']);

というように実行すれば、config('global.admin')abc@gmail.comを返すことができます。

global.とプリフィックスしたのは、単に他の変数と区別やグループ分けがしたいがためです。

ということは、DBからデータを読んでプログラムの実行時の最初に、configして入れしまえば良いわけです。

このための適切な場所は、プログラムの初期に実行される、app/Providers/AppServiceProvider.phpの中です。


namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use DB;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
	$setting = DB::table('setting')->pluck('value', 'key');

	config(['setting' => $setting]);        
    }
...
}

DBテーブルsettingの中身は、以下とすると、

+------------+---------------------+---------------------+------------------+-------------------+
| setting_id | created_at          | updated_at          | key              | value             |
+------------+---------------------+---------------------+------------------+-------------------+
|          1 | 2016-12-03 01:09:51 | 2016-12-03 01:09:51 | email_admin      | admin@gmail.com   | 
|          2 | 2016-12-03 01:09:51 | 2016-12-03 01:09:51 | email_from       | from@gmail.com    | 
|          3 | 2016-12-03 01:09:51 | 2016-12-03 01:09:51 | site_name        | ララジャパン       | 
+------------+---------------------+---------------------+------------------+-------------------+

例えば、config('setting')['site_name']の実行では、ララジャパンの値が返ってきます。

パブリックキーを使用してsftp

中規模のECを営む私のお客さんのところでは、自社製品を持ち出荷するゆえに、自社のウェブで販売するのみではなく、他社でのウェブサイトでも製品が売られています。となると、そこからも注文データが来ます。

その発注データは、ウェブサービスを使用したAPIを使用して取得、というようなものではなく、彼らが生成した注文データをCSVファイルとして指定のサーバーに置かれ、それを毎日sftpでダウンロードして、システム内に取り込みます。

また、逆に自社サイトで販売した注文情報を、出荷や解析の目的で他のサーバーにsftpでアップロードというケースもあります。

ここで重要なのは、パブリックキーを使用したsftpのコミュニケーションが必要なことです。

そこで登場するのが、以前会員編集フォーム紹介した、Laravel Collectiveです。

Laravel Collectiveのインストール

最初に、以下をコマンドラインで実行します。

$ composer require "laravelcollective/remote":"^5.3.0"

この実行で、必要なライブラリがインストールされ、composer.jsonが更新されます。

次に、config/app.phpのファイルをエディタで開き、以下を追加します。

  'providers' => [
    // ...
    Collective\Remote\RemoteServiceProvider::class,
    // ...
  ],

  'aliases' => [
    // ...
    'SSH' => Collective\Remote\RemoteFacade::class,
    // ...
  ],

設定

SSHのパッケージがインストールされたところで、次は設定です。Laravel用に開発されたパッケージでは、たいていはパッケージ独自の設定ファイルを、config/ディレクトリに作成します。

以下を、コマンドラインで実行してください。

$ php artisan vendor:publish --provider="Collective\Remote\RemoteServiceProvider"

この実行により、config/remote.phpの設定ファイルが作成されます。

エディターで、そのファイルを開き、acmeエントリーを追加します。acmeでなくても、名前はなんでもよいです。

  'default' => 'production',

  'connections' => [
        'production' => [
            'host'      => '',
            'username'  => '',
            'password'  => '',
            'key'       => '',
            'keytext'   => '',
            'keyphrase' => '',
            'agent'     => '',
            'timeout'   => 10,
        ],

        'acme' => [
            'host'      => env('ACME_HOST'), // sftp先
            'username'  => env('ACME_USERNAME'), // ログイン名
            'password'  => '', // 
            'key'       => base_path(env('ACME_KEY')), // パブリックキーファイルのパス名',
            'keytext'   => '',
            'keyphrase' => '', 
            'agent'     => '',
            'timeout'   => 10,
        ],
    ],

見ての通り、このファイルにはデフォルトとして、すでにproductionがありますが、それには触らず、ここではacmeの配列を新設しました。開発サイトでのテストも考えて、いろいろな情報をここで設定できるのは便利です。

今回は、バージョン管理にプライベートの値が入らないように、.envで指定するようにしました。特に、大きい値のパブリックキーを含むファイルを、keyで指定できるのも便利です。このファイルは、.gitignoreで必ずバージョン管理から排除が必要ですね。

keyphraseは、パブリックキーを生成したときに指定したパスワードを入れますが、パスワード指定なしで作成することが多いです。それでも十分セキュアであるのでここでは空とします。

.envでは、以下のような変数を追加します。

..
ACME_HOST=foo.google.com
ACME_USERNAME=foo
ACME_KEY=config/keys/test.pem
..

以上でテスト可能となります。もし、sftp先でsftpのみで設定されていないなら、

$ php artisan tinker

を実行して、接続テストができます。以下では、sshでacmeに接続して、lsコマンドを実行しました。

Psy Shell v0.7.2 (PHP 5.6.25 — cli) by Justin Hileman
>>> use SSH;
=> null
>>> SSH::into('acme')->run(['ls']);
[foo@acme] (acme) data.csv
=> null
>>> 

sftpでファイルのダウンロード・アップロード

ここまで来たら、あとは簡単です。プログラムの中で以下を実行するだけです。

ファイルのダウンロードは、

SSH::info('acme')->get('data.csv', storage_path('data.csv'));

ファイルのアップロードは、

SSH::info('acme')->put(storage_path('data.csv'), 'data.csv');

あたかも、コマンドラインで実行するような軽さですね。

Top