あーさーの備忘録

ゆっくり自由に生きてます

東日本大震災

急に思い出した話を書きます。

7年弱前に起きた東日本大震災。 (もうこんなに昔なんですね)

当時僕は中学2年生で、学校の体育館で3年生を送る会を行っていました。 突然の長い揺れ。ガラスの割れる音。

急いで教室に戻りテレビをつけると、大津波警報の文字が。 震源から数百km離れた沼津でも、保護者引き渡しとなりました。 家に帰るための国道は津波警報のため通行止めになりました。

中学の体育館は、新しいものができるまで立ち入り禁止になりました。 仙台の親戚の家は水たまりを残して跡形もなくなりました。 電池などの物資が不足し、大阪の友人が送ってくれました。

震災から1週間経ったある日、 国語の授業のはじめに先生がこんなことを言いました。

「大震災の報道を見て、 非日常に興奮してしまっている自分がいるんじゃないか。 みんなも自問自答してみてほしい。」

この発言は非常に衝撃的でした。 さして当事者でもない僕の気持ちを表現するに どれほど的を射た発言だったでしょうか。

多くの人が亡くなって、 生き残った人も過酷な避難生活を過ごして、 大規模な原発事故も起きて、

そんな状況に自分は興奮しているとするならば、 どれだけ残酷なことだろう、 と子どもながらショックを受けました。

こんなことをメディアで言ったら それこそ津波のような勢いで叩かれるでしょう。 しかしながら、それを的確な言葉で伝えた先生。 この立場だからこそできることだと思います。

不謹慎という言葉だけで片付けられるでしょうか。

ニュースや週刊誌に載っているのは他人の不幸ばかり。

これは人間の真理なのかもしれません。

「シン・ゴジラ」と舞台芸術に対する僕のスタンス

シン・ゴジラ

ご無沙汰しております、あーさーです。今日はこのブログ初めての技術系じゃないお話をします。

いきなりですが、「シン・ゴジラ」という映画をご覧になったことがありますか。この前の日曜に地上波初放映していたので、そのときに見たという人も多いと思います。まだ見ていない人はすぐにこのタブを閉じて、Amazonで円盤をポチってください。(以後、ネタバレの要素を含みます)

(アフィリエイトでは)ないです

演劇は問題提起の場

話は変わりますが、今回は僕の演劇に対する基本姿勢について書きます。僕は高校2年間を演劇同好会(今はもうなくなってしまったようですが)に所属して過ごしました。それまで、ラジオやテレビなどのメディアに出演したことはありますが、役者、舞台の経験は皆無でした。その当時、リーフレットに載せるためか、「演劇とは何か。」という質問をされたことがあります。それに対しての僕は、「演劇とは問いである」と答えました。

みなさんは舞台芸術を見て何を思いますか。ストーリーにただただ感動しますか。メッセージ性を感じますか。そもそも、舞台芸術というものはステージ上で完結しているものなのでしょうか。

演劇を見て、「やっぱり友情は大切だなぁ」とか「戦争はよくない」とか思うことは多いでしょう。でも、僕には、そんな単純なメッセージを伝えるためだけにその舞台があるとは思えないのです。物事にはそう簡単に白黒がつけられない、だからこれを見て観客も考えてみてほしい。そして、その観客の思考を含めた総合芸術が演劇であると考えます。

今、演劇という言葉を使っていますが、これは文学にも映画にも、あらゆる物語にも当てはまると思います。

シン・ゴジラ」に何を思うか

具体的に、「シン・ゴジラ」で考えてみましょう。第3形態(通称:品川くん)の際に自衛隊が攻撃しようとするも、逃げ遅れた民間人が近くにいたため、首相の判断で攻撃を取りやめたというストーリーがあります。この時、あなたは何を思いましたか。

  • このときに躊躇わず攻撃していれば、後の災難は起こらなかった
  • 人命第一のこの決断は正しい
  • これは首相が判断することではない

いろいろな意見があると思います。しかし、これらのどれが正義なのかということは、作品中では触れられていません。確かに事実はあり結果はあれど、何が正しいのか、そう簡単に決めることができる問題ではないのです。

他にも、役人は無能だとか、日本社会は形式に囚われすぎているとか、核開発や遺伝子研究はよくないとか、アメリカの言いなりになってはいけないとか、この作品を見ていろんなことを思うでしょう。でも、それは「シン・ゴジラ」という作品が観客に届けたかったメッセージではないと思うのです。これはあくまで結果でしかないのです。

でも、「考える」ことって、とても楽しくないですか?

そして、自分が考えたことを他の人と議論できたら、より意見が深まって、楽しくないですか?

そう、これが「シン・ゴジラ」が提供する副次的なエンターテインメントです。ストーリーを見て楽しい、面白いことを言っているから楽しい、それは映画を見ているその時に感じる面白さ。もちろんそれがメインなのですが、提起された問題について考えてみる、それは映画館の外でもできます。映画の上映時間以上に楽しめるというわけです。

ハッピーエンドも悪くないけど

これは個人的な価値観なのですが、僕は物語におけるハッピーエンドはあまり好きではありません。かといって、バッドエンドが好きなのかと言われるとそうでもありませんが。終演後にどれだけ観客の脳裏に余韻を残せるか、ということがポイントだと思います。一般的なハッピーエンドだと、「2人は幸せなキスをして終了」といったように、はいはいよかったね、ということで終わってしまうんですよね。見ててスッキリはしますが。

シン・ゴジラ」の最後はどうだったでしょうか。僕は初見では気づかなかったのですが、ゴジラの尻尾から何か子供のようなものが生まれるというシーンを最後に映画が終わります。この後の日本に何が起こるのか、わくわくしますよね。

こういう遊びが用意されている演劇を見に行くと、僕は劇場から家に帰るときにずっと考えてしまいます。同じチケット代を払うのであれば他人より楽しみたいものですね。

舞台を作る人間として

少し話が逸れてしまいましたが、裏を返せば、演劇をやっている私はこういったことも考えて本を書いたり、演出したりしないといけないわけですね。偉そうに書いてますけど僕にはまだ無理でした。ちゃんと勉強すべきなんでしょうけど、する場もないのでひたすら小説読んでます。文系の授業でこういう感じのあればいいですけどね。

ここまで長々と語ってきましたが、僕が考えていることが真理だとはこれっぽっちも思っていません。僕がこう考えているというだけです。これもまた、そう簡単に白黒つけられる問題でもないでしょうから。

世界はそんなに単純にできていない

なにか伝えたい事があって、それを芸術に昇華させる、という人も多いと思います。でも、僕には伝えたい事が思いつきません。一般的にものを言うことって、凡人にはとてもむずかしいことです。周りを見回すと、様々な問題があります。あるものが部分的に悪いから、それをすべて否定してしまおうと考える人が世の中には多すぎる気がします。その逆も然りです。もしそんなにすぐ答えが見つかるなら、世界はとっくに不満のない素晴らしい世界になっていることでしょう。考えることも大事ですが、自分とは違う視点の意見を大事にすることも忘れてはいけませんね。

ファイルアップロードの際に文字化けする問題を解消する

あるサーバー

私の環境ではないが、 CORESERVER あるサーバーで、「ファイルアップロードの際にファイル名からフィールド名まで文字化けしてしまう」という問題が発生したので、解消するためのメモ。

文字コードがおかしい?

最初はmb_internal_encodingが違う値なのかなぁとか適当に考えて文字コードを変換して見たが、上手くいかない。まず、文字化けの仕方がいつも見慣れるようなタイプではないので、何から何にエンコードされているのかが分からない。メジャーな文字コードの組み合わせで試してみても、同じような文字化けを再現できませんでした。

困ったときのphpinfo()

ということで、phpinfo()の結果を、自分の環境と比べてみた。狙いをmbstring系に絞って差分を取ってみると、いかにも怪しそうな名前の設定が見つかった。

mbstring.http_input = auto;

mbstring.encoding_translationとは

mbstring.encoding_translationというものがあるらしく、$_POST$_GET文字コードを、スクリプト上で変換しなくても自動でやってくれるらしい。正直自分でやるから勝手にやらないでほしい。とりあえずinputの場合だけ書き換えてみる。

mbstring.http_input = "pass";

デフォルト値に戻してみた。すると、文字化けも直った。やったぜ。

ちなみにこの設定は古いものらしく、PHP5.6~は非推奨になっている。とりあえず空にしておけばいいらしい。

PHP: 実行時設定 - Manual

FuelPHPで日本語URLを扱う

FuelPHPって日本語URL使えるの?

FuelPHPは自動でURLからリクエストを処理するController、actionを指定します。その関係で、クラス名・メソッド名に日本語や%が使えない以上、日本語URLは扱えない、と思っていたのですが、routes.phpというConfigファイルを思い出しました。

結論を言うと、日本語URLは、できます!!

日本語URLを使う方法

APPPATH/config/routes.php

<?php
return array(
    '_root_'  => 'index',  // The default route
    '_404_'   => '404/index',    // The main 404 route
    'hello(/:name)?' => array('welcome/hello', 'name' => 'hello'),
    'テスト' => 'test/index',  // ←ここ追記
);

こんな感じで日本語と、それに対応するController名/action名を配列に追加すると、アクセスできちゃいます。

元のURLでアクセスしてきた人を弾く

URLの正規化のために、test/indexとアルファベットのURLでアクセスしてきた人を弾く方法は、Uriクラスを使うことで簡単にできます。詳しくはあまり興味が無いので書きません。

自分でさえ興味のない誰得な記事を書いてしまった……。

FuelPHPのEmailパッケージでSMTP-AUTHを使用して送信する

Emailパッケージ

久々にFuelPHPの話です。FuelPHPには便利なEmailパッケージが同梱されていて、メールをphp標準のmail()関数を使わなくてもメールが送れます。使用方法は以下の通り。

<?php
$email = Email::forge();
$email->subject(mb_convert_encoding('テストメール', 'ISO-2022-JP'))
      ->body(mb_convert_encoding(View::forge('mail', [], false), 'ISO-2022-JP'))
      ->to('hoge@hoge.com')
      ->from('huga@huga.com', mb_convert_encoding('ぽよぽよ', 'ISO-2022-JP'));
try
{
    $email->send();
}
catch (\EmailValidationFailedException $e)
{
    // メールアドレスが正しい形式じゃないとき
}
catch (\EmailSendingFailedException $e)
{
    // ドライバがメールの送信に失敗したとき
}

同様の方法でbccやccを設定したり、添付ファイルをつけたりなんてこともできます。View::forge()の第2引数に配列を渡したり、予めViewオブジェクトを生成し$view->hoge = 'hoge';とプロパティを指定してあげることで、変数を使ってメール本文を生成することもできます。詳しくは、FuelPHPのドキュメントを読んでください。

Usage - Email Package - FuelPHP Documentation

Emailパッケージのデフォルト設定の問題

さて、このEmailパッケージを導入する手順で、APPPATH/configにemail.phpというEmailパッケージの設定ファイルを設置します。こちらの設定ファイルは、文字コードISO-2022-JPエンコードを7bitにする以外に弄ることがなかったのですが、ある時急に思い出しました。

あれ、SMTP認証してなくね?

すぐさまconfigファイルを覗くとこんな設定がありました。

APPPATH/config/email.php

<?php
return array(
    //117行目付近
    /**
     * SMTP settings
     */
    'smtp' => array(
        'host'     => '',
        'port'     => 25,
        'username' => '',
        'password' => '',
        'timeout'  => 5,
        'starttls' => false,
    ),
);

今更ですけどPHPってプログラム部分が<?php ?>で囲われてるせいで、ブログでsyntax highlightするのにいちいち<?phpってつけなきゃいけないんですよね。見た目が煩雑になるので嫌ですね。

そんなことはさておき、SMTP settingsという設定を見つけ、その中には25の文字が!あ~、25番ポートで送ってたのか~。じゃあこの設定をちゃんと埋めればいいんですね。

Configを弄る

だいたいの環境ではメールアドレスごとにusernameが異なるはずなのですが、デフォルト設定を書き換えるだけだと1種類のアドレスからしか送れない…。もちろんこちらのConfigファイルに新しいプロファイルを作成(setupのところに配列を追加)すればいいのですが、この設定そんなにたくさん使わない!ということもあるでしょうし、今回はEmail::forge()の第2引数に設定を追記していく形で設定していきます。

<?php
$email = Email::forge('default', [
    'smtp' => [
        'host'     => 'poyopoyo.com',
        'port'     => 587, //サブミッションポート
        'username' => 'poyo@poyopoyo.com',
        'password' => '********',
        'timeout'  => 5,
        'starttls' => false,
    ],
]);

メールソフトを設定するような気持ちで入力すればOKです。これで送ってみたのですが、ポートが変わらない……どころかパスワードが違っても送れてしまう始末。たしかにこのEmailインスタンスには設定情報が入っているのですが……。

driver設定を追加

FuelPHPのEmailパッケージのドキュメントはお世辞にもしっかりしているとは言えない(情報量が少ない)ので、仕方なくコードをひたすら読んでいきました。すると、こんな設定があることがわかりました。

APPPATH/config/email.php

<?php
return array(
    //48行目付近
    /**
     * Mail driver (mail, smtp, sendmail, noop)
     */
    'driver' => 'mail',
);

この値をsmtpにしないとsmtpの設定が反映されないようですね。

先程のconfig配列に追記します。

<?php
$email = Email::forge('default', [
    'smtp' => [
        'host'     => 'poyopoyo.com',
        'port'     => 587,
        'username' => 'poyo@poyopoyo.com',
        'password' => '********',
        'timeout'  => 5,
        'starttls' => false,
    ],
]);

これでメールを送ってみると、見事にSMTP-AUTHを使用して587ポートからの送信に成功しました。

おまけ①SSLを使う

<?php
$email = Email::forge('default', [
    'smtp' => [
        'host'     => 'poyopoyo.com',
        'port'     => 465,
        'username' => 'poyo@poyopoyo.com',
        'password' => '********',
        'timeout'  => 5,
        'starttls' => true,
    ],
]);

これでSTARTTLSで接続できるかなぁと思ったのですが、残念ながら、私の環境では以下のエラーが発生し、認証ができませんでした。

ERROR - ***time*** –> Notice - fputs(): send of 6 bytes failed with errno=32 Broken pipe in ***path*** on line ***line***

私の設定が間違っている可能性のほうが高いので、またいつか試してみます。誰か原因が分かる人がいたら教えてください。

2017/09/26 16:37追記(できました)

hostsの値の前にssl://をつけたらふつうにできました。おかしいな、朝はこれでダメだったのにな。

<?php
$email = Email::forge('default', [
    'smtp' => [
        'host'     => 'ssl://poyopoyo.com',
        'port'     => 465,
        'username' => 'poyo@poyopoyo.com',
        'password' => '********',
        'timeout'  => 5,
        'starttls' => true,
    ],
]);

おまけ②mailドライバーは何だったのか

デフォルトで指定されていたdriver => 'mail'はどんな処理をしているのかな、と思ってソースを覗いてみました。そこには@mailの文字が…!!。結局mail()使ってるんか~い。まぁ確かに認証情報ないなら使わないと送れないんですけどね。初めてお目にかかった関数前の@ですが、エラーを出力しないようにするエラー制御演算子というものらしい。なるほど。あまり使用は推奨されていないようだけど。

Youtubeのデザイン変更とCustom Elements

Youtubeのデザインが変わった

静岡からこんばんは。あーさーです。ところで、誰もが知っている動画サイトYoutube(https://www.youtube.com/?gl=JP&hl=ja)のデザインが変わったのをご存知でしょうか。マテリアルデザインを取り入れ、スッキリしたレイアウトになりました。また、グレーテーマに変更できるようになりました。ドロワーメニューを開いたときに、スクロールバーの有無でレイアウトが若干ズレるのが気になりますが、とてもスタイリッシュなデザインだなぁと思います。

せっかくなのでコードの中身を見てみたのですが、<app-drawer><yt-icon>などという見慣れない要素を見かけました。要素名に-を使っていることからCustom Elementsで間違いなさそうですね。

Custom Elementsとは?

独自の要素を定義して、よりセマンティックなマークアップができるようにする、Web Componentsの仕様の1つです。Web Componentsには他にもTemplatesやShadow DOMなど、あらゆる部品をコンポーネント化して再利用しやすく、かつ外部を汚染しないようにする仕様が含まれています。詳しくは、このあたりの記事が分かりやすいので参考にしてください。

qiita.com

liginc.co.jp

Custom Elementsを使うと、今まで

<div class="error">
    <h3 class="error_headline">エラー</h3>
    <ul class="error_list">
        <li>「名前」は必須事項です。</li>
        <li>「年齢」は半角数字で入力してください。</li>
    </ul>
</div>

と、既存のタグにBEMなどの命名規則を利用してエセコンポーネント化していたものが、

<error-box>
    <error-headline>エラー</error-headline>
    <error-list>
        <error-element>「名前」は必須事項です。</error-element>
        <error-element>「年齢」は半角数字で入力してください。</error-element>
    </error-list>
</error-box>

のようにマークアップできるようになります。syntax highlightが上手く対応してくれていませんが……。見ただけで何の部品化分かりやすいですし、いちいちクラスをつけなくても良いし、マークアップしてる感がすごいです。

Custom Elementsの使い方

勝手に独自要素を作るだけではレイアウトするのにブラウザが困ってしまうので、Javascriptでちゃんと定義してあげる必要があります。

document.regisiterElement()というメソッドを使用します。Custom Elementsで作る要素の名前には必ず-を含む必要があります。そうしないと既存のタグとの住み分けができませんからね。

var errorBox = document.registerElement('error-box');

他にも既存のタグを継承して……など細かいところがいろいろあるのですが、自分で説明するよりほかのサイトを見たほうが分かりやすいので、前述のリンクをご参照ください。

Custom Elementsサポート状況

いつもお世話になっているcaniuse(http://caniuse.com)で確認したところ、ChromeOperaでは対応しているようなのですが、Firefoxではin-development、EdgeではUnder Considerationということで、まだまだ本格的に利用できるわけではなさそうです。あれ、じゃあYoutubeはどうやって他ブラウザ対応しているんだろう。IEの開発者ツールで見たら普通にdivとかbuttonとかのタグに置き換わっていました。

どのように要素を作るのか、ShadowDOMの使い方、非対応ブラウザの対応方法、いろいろ調べてみたかったのですが眠いので今日はここまでにしようと思います。

maildropのmailfilterで受信メールをプログラムの標準入力に渡す

こんにちは、最近水曜日のカンパネラにハマっているあーさーです。

maildropとは

今日は、maildropの.mailfilterという振り分け機能のようなものを使用して、受信したメールをプログラムにの標準入力に渡す方法をご紹介します。maildropっていうのはiCloudの話ではなく、MDA(Mail Delivery Agent)といって、届いたメールをメールボックスまで配達するプログラムの一種です。有名なレンタルサーバーだと、さくらのレンタルサーバー(http://www.sakura.ne.jp/)やエックスサーバー(https://www.xserver.ne.jp/)などがmaildropを使用しています。今回はこの2社のレンタルサーバーでの設定方法を載せておきます。

mailfilterの場所

mailfilterとは、文字通り届いたメールが通る振り分けプログラムのようなものになります。このファイルの場所はレンタルサーバーによって違うのですが、さくらとエックスサーバーの場合を載せておくので参考にしてください。

さくらのレンタルサーバーの場合

/home/[サーバーID]/MailBox/[アドレス名]/.mailfilter

よく見ると.procmailrcや.forwardというファイルもあるので、maildropではなくてprocmailを使っているのかもしれませんね。実際Webサイトを見るとprocmailのパスが掲載されていますし。でも.mailfilterの書き方がprocmailじゃないんだよなぁ……

エックスサーバーの場合

/home/[サーバーID]/[ドメイン名]/mail/[サブドメイン]/[アドレス名]/.alias

エックスサーバーの方はちょっとディレクトリが複雑ですね。エックスサーバーにも.mailfilterというファイルが有るのですが、このファイルで他のいろいろなスクリプトを読み込んでいる感じなので、そこで読み込まれている.aliasファイルに記述するのが無難だと思います。

mailfilterの書き方

例えば、spamspam.spamから来たメールをgomibakoディレクトリに配達する場合は、下のように書きます。

if (/^From: spam@spam.spam/:h)
{
    to "/gomibako/"
}

/~/の部分はおなじみの正規表現です。:hと書くことでヘッダのみにマッチさせます。to "[ディレクトリ]"で指定したディレクトリにメールを配達し、配達を終了します。toではなくccを使うことで、配達を終了させずに処理を終了させることができます。また、exitと書くことでも配達処理を終了できます。ディレクトリを入れる部分に"! hoge@hoge.com"と!とメールアドレスを入れることで、指定したメールアドレスにメールを送ることができます。たとえば、

cc "! poyo@poyo.com"
cc "! fuga@fuga.com"

と書くことで、届いたメールを2メールアドレスに転送させることができます。これ使えばメーリングリストとか簡単に作れる気がしてきます。

届いたメールをプログラムに渡す

これを応用することで、届いたメールをプログラムの標準入力に渡すことが出来ます。例えば、ログファイルを生成したり、メールが届いたという通知をLINEやDiscordに送ったりできます。可能性は無限大です。今回はPHPを使ってみます(というより私がPHP以外まともに書けない)。

cc "| /usr/bin/php7.0 /home/hoge/hoge.com/script/notification.php"
exit

シェルコマンドで御用達のパイプが登場します。cc "| [PHPのパス] [スクリプトのパス]"と記述すると届いたメールがスクリプトの標準入力に渡されプログラムが実行されます。最後のexitは書かなくてもいいですが、書いておくとメールボックスにメールが保存されなくなります。

スクリプトを書く

次に、渡されるスクリプト側を書きます。メールのデータを解析するのに、今回はPEARのMail::mimeDecodeを使用します。導入方法は他のサイトでも探してください。惰性でPEAR使ったのですが、もしかしたらphp-mime-mail-parserというライブラリ使ったほうが記述が楽かもしれませんね。気力があったらこちらを使った方法も後日書きたいと思います。

#!/usr/bin/php7.0
<?php
//PEARのMail_mimeDecodeを読み込む
require_once('/home/hoge/hoge.jp/pear/PEAR/Mail/mimeDecode.php');
//文字コードはUTF-8で日本語だよ
mb_internal_encoding('UTF-8');
mb_language('japanese');
//メールのデータが標準入力に渡されるのでそれを$sourceに格納
$source = file_get_contents("php://stdin");
if (!$source) {
    die('Error');
}
//Mail_mimeDecodeの設定
$decode_opt = array(
    'include_bodies' => true,
    'decode_bodies'  => true,
    'decode_headers' => true,
);
$decoder = new Mail_mimeDecode($source);
$mail_data = $decoder->decode($decode_opt);
//メールの内容をUTF-8にエンコードしてそれぞれ変数に格納
$from = mb_convert_encoding($mail_data->headers['from'], 'UTF-8', 'ISO-2022-JP,UTF-8,SJIS');
$subject = mb_convert_encoding($mail_data->headers['subject'], 'UTF-8', 'ISO-2022-JP,UTF-8,SJIS');
$ctype = strtolower($mail_data->ctype_primary);
if ($ctype === 'multipart') {
    foreach ($mail_data->parts as $part)
    {
        if (strtolower($part->ctype_primary) === 'text' and strtolower($part->ctype_secondary) === 'plain') {
            $body = "\n" . mb_convert_encoding($part->body, 'UTF-8', 'ISO-2022-JP,UTF-8,SJIS');
        }
    }
}
elseif ($ctype === 'text') {
    $body = "\n" . mb_convert_encoding($mail_data->body, 'UTF-8', 'ISO-2022-JP,UTF-8,SJIS');
}
else {
    die('Error');
}

HTMLメールとかいう害悪のせいで若干複雑になっていますね。これで、$body・$from・$subjectにそれぞれ目的のデータが格納されます。文字コードEUCじゃないと動かないと書いてあるサイトもありましたがとりあえずはUTF-8で大丈夫そうです。気をつけてほしいことが2点あります。

1点目は、プログラムの最初に、#!/usr/bin/php7.0PHPのパスを書くことです。これはPHP以外の言語を使用する場合も同じなので気をつけてください。

2点目は、プログラムが異常終了すると、メール送信者にエラーメールが届くことです。このプログラムだと、die()が実行されてしまう場合はエラーメールが届いてしまいます。他にも、些細なsyntax errorなどでいちいちエラーメールを生成するので、作成時はメールを送ってチェックするのではなく、メールのデータを直接渡してコマンドラインで実行させるなどすると良いと思います。

ここまで書けたら、あとはstream_context_create()してWebhookにPOST送ってあげるとメール通知プログラムの完成です。PHPfile_get_contents()が優秀すぎてつらいです。