LaravelでCSRFトークンを入れているのに419 PAGE EXPIRED

LaravelでPOSTリクエスト等を送信する場合は、CSRF対策用のトークンをhiddenタグにセットします。通常@csrfディレクティブを<form></form>の中に入れることで、hiddenタグが自動生成されます。

これを入れ忘れて、フォーム送信時に419 PAGE EXPIREDというエラーを発生させるのが、よくやりがちなミスですが、今回@csrfを入れているのにも関わらず、419エラーが発生することがありました。

他で紹介されているキャッシュやセッションファイルの削除等を試しましたが、エラーが解消されず、色々と調べた結果、POSTリクエストに含まれる変数の数(inputタグ等の数)が多すぎたため、PHPの設定により上記トークンを含むリクエストの一部が削除されてしまっていたことが分かりました。

php.iniのmax_input_varsという項目を設定することで解消しました。(初期値は1000)

; How many GET/POST/COOKIE input variables may be accepted
max_input_vars = 100000

リクエストのデータサイズが大きい場合は、次の設定も更新する必要があります。

; Maximum size of POST data that PHP will accept.
; Its value may be 0 to disable the limit. It is ignored if POST data reading
; is disabled through enable_post_data_reading.
; http://php.net/post-max-size
post_max_size = 64M

; Maximum allowed size for uploaded files.
; http://php.net/upload-max-filesize
upload_max_filesize = 64M

LaravelのMailableでコールバックを設定

LaravelではMailableクラスを使用することで、メールの組み立てと送信を簡単に行うことができます。

Mailableクラスを作成するには、artisanコマンドを使うと簡単です。

$ php artisan make:mail MyMailable

このコマンドを実行すると、app/Mail/MyMailable.phpというファイルが作成され、中身は次のようになります。

<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class MyMailable extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->view('view.name');
    }
}

buildメソッドの戻り値として、レンダリングされたテンプレートを返すことで、メッセージの送信が完了します。

メッセージの送信後に実行したい処理がある場合は、Mailableクラスのcallbacksプロパティ(配列)に関数をセットします。コールバック関数の引数には$message(Messageオブジェクト)が渡されるため、$message->getId()でメールサーバーから返されたMessage-IDを取得することもできます。

    public function build()
    {
        $this->callbacks[] = function($message) {
            // 送信後に実行したい処理
        };
        return $this->view('view.name');
    }

ユーザーを指定してcronを実行

Laravelでタスクスケジュールを利用する場合、cronに次のエントリを追加します。

* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1

タスク内でログ出力をする際には、Webと同様にLoggerが使用できますが、cronをrootユーザーで実行してしまうと、ログファイルの所有者がrootになってしまいます。

そのため、WebサーバーにApacheを利用している場合、Web側がログを出力する際にパーミッションエラーが発生する場合があります。

これを避けるためには、apacheユーザーとしてcronジョブを設定するのが良いと思います。

$ crontab -u apache -e

LaravelでSSL certificate problem

LaravelでFacebookOAuth認証を行おうとしたところ、以下のようなエラーが発生しました。

RequestException in CurlFactory.php line 187:
cURL error 60: SSL certificate problem: unable to get local issuer certificate (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)

調査の結果、CA証明書がphp.iniで正しく設定されていないことが原因であると分かりました。

http://curl.haxx.se/ca/cacert.pem

をダウンロードして、「C:\php\cacert.pem」として保存し、php.iniに以下の記述を加えることで、エラーが解消されました。

[curl]
; A default value for the CURLOPT_CAINFO option. This is required to be an
; absolute path.
curl.cainfo=C:\php\cacert.pem

LaravelのmigrateでPDOException

Laravelでmigrateコマンドを使用したところ、PDOException(could no find driver)が発生しました。

$ php artisan migrate
**************************************
*     Application In Production!     *
**************************************

 Do you really wish to run this command? [y/N] (yes/no) [no]:
 > yes



  [PDOException]
  could not find driver

調査の結果、php.iniのMySQL拡張がコメントされているという凡ミスでした。「;」を外して、再度実行すると正しく処理されました。

$ vi php.ini

...
;extension=php_pdo_mysql.dll
...

LaravelでCouldn’t find preset “es2015″エラー

Laravelプロジェクトを新しく作成し、gulpを通じてelixirを実行したところ、以下のようなエラーが出ました。

これを解決するには、以下の二つのパッケージをインストールする必要があるようです。

$ npm install babel-preset-es2015 --save
$ npm install babel-preset-react --save

こちらの議論では、npmをアップグレードすれば解決するとの発言もありますが、私の環境ではうまくいきませんでした。

Laravelコマンドのまとめ

最近、PHPのフレームワークの中で一番勢いがあるLaravelで使用するコマンドのまとめです。

Webサーバーを起動

開発用のWebサーバーを起動します。デフォルトのURLはhttp://localhost:8000になります。

$ php artisan serve

データベースのマイグレート

database/migrations以下のマイグレーションスクリプトに従って、データベースに変更を加えます。

$ php artisan migrate

 

Top