名もなき未知

エンジニアリングとか、日常とかそういうのをまとめる場所。アクセス解析のためGAを利用、Googleに情報を送信しています。商品紹介のためAmazonアフィリエイトを利用、Amazonに情報を送信しています。記事に関しては私が書いていない引用文を除いて自由にご利用ください。

GuzzleでHTTP通信してみる

PHPでモダンな感じで HTTP 通信するなら何?みたいな話をいつだったかしていました。

どうやら Guzzle が流行ってるらしい、とのことだったので、試しに Authorizationリクエストヘッダも含めた HTTP 通信をしてみることにしました。

なお、5年ぶりくらいに PHP を触ったので、連想配列を書くだけでも苦戦してました(他言語の書き方に慣れすぎたか…)。まあ思い出したけど。

やったこと

まず Docker で Guzzle を入れる

正直ここが一番大変だったといっても過言ではないです。

背景としては、特に普段から PHP を書いていないのでローカルに開発環境は不要と思い、実行環境だけあればよい気持ちになったためです。

Overview — Guzzle Documentation を見ている限りでは、 composer で入れるのが良いらしいですね。

ちょっと調べると composer も Docker Image があることを知りました。やったー。

というわけで下記の2つを使ってマルチステージビルドしました。

というわけで Dockerfile は下記になりました。

FROM php:8.0-fpm-buster

# composer はマルチステージビルドで持ってくる
# refer: https://qiita.com/yatsbashy/items/02bbbebbfe7e5a5976bc
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# composer need git
RUN apt-get update && apt-get install -y git

RUN composer require guzzlehttp/guzzle:^7.0
COPY . .
RUN chmod u+x entrypoint.sh

ENTRYPOINT ["/var/www/html/entrypoint.sh"]
# RUN ["php", "main.php"]

よくわかってないのですが、なぜか WORKDIR が /var/www/html/ になっているので(composerのせいか?) ENTRYPOINT はそこに合わせています(デバッグするときは ENTRYPOINT 外して、雑に exec -it {image_id} bash で入ってデバッグしていた)。

Guzzle でリクエストをする

Qiita の API でも試しに叩いてみることにします。認証しているユーザーを返す API がある GET /authenticated_user のでそれをたたいてみることにします。

基本的には Client を作って、リクエストして、結果を受け取る形です。下記のページを参照に作っていきます。

出来上がったものがこちら。

<?php

require 'vendor/autoload.php';

$token = getenv('QIITA_ACCESS_TOKEN');

$client = new \GuzzleHttp\Client(
    [
        'base_uri' => 'https://qiita.com',
        'timeout' => 2.0,
    ]
);

$headers = [
    'Content-Type' => 'application/json;charset=utf-8',
    'Authorization' => 'Bearer '.$token,
];

$res = $client->request(
    'GET', '/api/v2/authenticated_user', [
        'headers' => $headers
    ]
);

echo $res->getStatusCode()."\n";
echo $res->getHeaderLine('content-type')."\n";
echo $res->getBody()."\n";

token は直打ちするとよろしくないので、環境変数からとる形にしています。

環境変数を渡しつつ実行する

最後に虚無みたいな entrypoint.sh を作っておくことにします。

#!/bin/bash

php main.php

まずはビルドします。

❯ docker build . -t php-practice
Sending build context to Docker daemon  4.608kB
Step 1/7 : FROM php:8.0-fpm-buster
 ---> 4ebd60322a2b
Step 2/7 : COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
 ---> Using cache
 ---> 49f3a96a6383
Step 3/7 : RUN apt-get update && apt-get install -y git
 ---> Using cache
 ---> 0bd8cb7267ee
Step 4/7 : RUN composer require guzzlehttp/guzzle:^7.0
 ---> Using cache
 ---> ea788036ebab
Step 5/7 : COPY . .
 ---> Using cache
 ---> a5fb0b2fa934
Step 6/7 : RUN chmod u+x entrypoint.sh
 ---> Using cache
 ---> 3db87772286c
Step 7/7 : ENTRYPOINT ["/var/www/html/entrypoint.sh"]
 ---> Using cache
 ---> ee0a466366fd
Successfully built ee0a466366fd
Successfully tagged php-practice:latest

で、うまくいったら run します。 ENTRYPOINT を指定してるし、 run したら消していいはずなので --rm つけてます。

トークンは Qiita のユーザーページから発行してください。

❯ docker run  -e QIITA_ACCESS_TOKEN=${PEKOPEKO} -t php-practice --rm
200
application/json; charset=utf-8
{"description":"えんじにゃー。ぷりぷりかしこま。Pythonしかできない。","facebook_id":"","followees_count":19,"followers_count":21,"github_login_name":"yumechi","id":"yumechi","items_count":9,"linkedin_id":"","location":"東京","name":"Senri Yumechi","organization":"","permanent_id":72473,"profile_image_url":"ほげほげ","team_only":false,"twitter_screen_name":"__yumechi","website_url":"https://namonakimichi.hatenablog.com/","image_monthly_upload_limit":104857600,"image_monthly_upload_remaining":104857600}

ちょっとやばそうなところは雑にマスクしましたが、無事に実行できました。やったね。

まとめ

やっぱり Docker ! マルチステージビルド ! はいいですね。ローカル環境が汚れにくいし、再現性もあっていい感じです。

環境変数も実行時に入れることによって、挙動を制御することもできるので、活用していきたいですね。

そして Guzzle ですが、ヘッダーの設定、リクエストの受付、そのあたり見ても他の言語の通信と大差ない感じで扱えて非常に楽でした。

cURL でリクエストする方法も知っていますが、 Guzzle にはどうやらまだ使いこなせていない機能でいいもんがたくさんありそうです。

PHP でなにかつくるかはわかりませんが、頭の片隅には入れておこうと思います。

追記

静的解析も少しやったんだった。この記事を参考にした。

PHPの静的解析いろいろ - Qiita

php -l <filename> はガバガバなので何も出なかった。

phpcs を試して多少おこられたので直しました( main.php はこれに従って直した)。

ほかについては試してませんが、 CI とか回すときにコードチェックもついでにできるようになるといいかもしれないですね (希望的観測)。

これで今度こそ終わり。

Node.js で Gmail を使って smtp でメールを送る…(が思ったより大変だった)

思ったよりもタイヘンデシタネー;;

やったこと

主な流れとして

  • nodejs の nodemailer でメールを送る
    • node-sendmail を使おうとしたが、うまくいかなかった
    • いろいろしらべた & node.js awesomeを見ている感じでは、 nodemailer が人気ありそうな感じだった
  • googleの Oauth 認証を使う
    • ローカルから雑に送ろうとしたが、うまくいかない感じだったので
    • 現実的に Google の認証を通して送るのはあり得るユースケースだと思ったので
  • 変数に情報を直打ちしない
    • どう考えても危ないので
    • あとは開発環境を切り替えること想定での開発をしたほうが良いので
    • 環境変数からとってそれを反映する形にしたい

基本的にはこの記事が参考になりました。

node.js 上の nodemailer で OAuth 2.0 を使って gmail からメールを送る · GitHub

gmail の認証周りの設定をしていく

最初ベタに mail address と password による認証を行うのですが、あまりに慣れていないので大変でした…。

やった手順は参考手順とほぼ一緒なので、箇条書きにだけすると

  • Google API Console へ行く
  • 必要に応じて新しいプロジェクトを作る
  • OAuth同意画面で、認証用アプリケーションを定義する(Test Applicationとかにした)
    • アプリケーションのテストユーザーに自分のアカウントを追加しておく必要があるかも(後段の認証プロセスで失敗したので)
  • 認証情報から OAuth クライアントIDを発行する
  • OAuth 2.0 Playground で各種設定をして、認証トークンを発行する
  • 発行されたトークンをメモっておく

表示名などは変わっているものもあったので、探すのが大変でした。

nodemailer で送信する

この辺を読んで実装する。

nodemailer.com

stackoverflow.com

stackoverflow.com

ポイント?としては下記です。

  • auth 用の dict を渡す必要がある
  • トークンは今まで集めたものをそれっぽく…(というか指定通り入れれば迷うことはないような気がする)
  • transporter の stmp は smtp.gmail.com にする
    • gmail となってるものをいくつか見た気がするが、自分はうまく動かなかった

直打ちをやめる

.env に書き出すようにして dotenv から読むようにしました。

特に語ることなし。トークン名がプログラム上から消えたので、安心してさらせるようになる。

できたもの

プログラムが短いのでブログにそのまま貼ってみる。

const nodemailer = require("nodemailer");
require("dotenv").config()

const auth = {
  type: "OAuth2",
  user: process.env.SENDER_EMAIL_ADDRESS,
  clientId: process.env.CLIENT_ID,
  clientSecret: process.env.CLIENT_SECRET,
  refreshToken: process.env.REFRESH_TOKEN,
}

const transporter = nodemailer.createTransport({      
  host: "smtp.gmail.com",
  secure: true,
  auth: auth,
});

const mailContent = {
  to: process.env.RECEIVER_EMAIL_ADDRESS,
  subject: "テストメール",
  text: "ほんぶんにゃ",
};

transporter.sendMail(mailContent, function (error, info) {
  if (error) {
    console.log(error);
  } else {
    console.log('Email sent: ' + info.response);
  }
});

ほか

一応参照した。

qiita.com

迷惑メールにいるかもね、とかパスワード間違ってるかもね、みたいなところで参照した。

qiita.com

感想

サクッとメール出したいだけだったのですが、思いのほかはまって大変でした。

そのうち postfix 入れてそこから投げる、みたいなことにも挑戦してみたいですね。

ただメール送信、メール受信に関しての知識がまだまだ薄いので、この辺りも一回がっつりと勉強してみたさがあります(実運用上は Saas を使うのが筋だと思いますが、ローカルでの開発とかデバッグとかで使えなくはなさそう)。

なんとなく postfixdovecot が大事なのは知っていますが、時代的にあっているかどうか、みたいなところとか、いろいろ気になる部分はあります。

いやでもあれかな、 AWSのSESとかでやってみるのが先なのかも…?

LINE や twitter といったところで最新情報を得るパターンもそれなりに増えてきましたが、メールマガジンのような流れにくく長い広告などはやっぱりメールで受け取る方がうれしいのかなと思います。

そういう意味でもまだまだメールに関して理解を深めていくのは価値があることかもしれないですね…(?)。

追記

コードはここに挙げた

https://github.com/yumechi/send-mail-sample

Electronを始めるためにElectronで書かれたものを読むことにする

ローカルで動くようなクライアントアプリを作ってみようかなと思ったのですが、とりあえずOSに縛られるのは嫌でしょと思ったので Electron でも入門しようかなと思いました。

ちょうど知ってるところで Electron 製のアプリがあるな~~と思ったので、読んでました(おい)。

github.com

併せてこちらの公式ドキュメントもたまに見ています。

www.electronjs.org

読んだ感想として

  • とりあえずメインとなるエントリーポイントを定義してやって、そこからさらに画面のベースとなるようなものを呼び出す
  • 画面を構成するのは html なのでフレームワークとかでコンパイル後の html, js, css 読ませてもよい
    * 実運用を考えると、何かしろのフレームワークでは書きたい
    * 上記アプリは Vue を使って書かれていました( VueJS は前軽ーく触ってからそれっきりなので、学びなおせた)
    
  • VueJS のコンポーネントの分け方とかわからんとか思ってたけど、読んだらかなり理解がはかどった
    * 得意な人たちの得意領域のコードを読むのは大変参考になる
    * 自分も得意な領域でのコードならこう書ける、みたいなのをスマートに呈示できるとよいのかもなぁ
    
  • Nucleus 自体知らなかった https://www.nucleus.sh/
    * GAから外れたところの分析ツール、そういえば知らない
    
  • ejs ってなんだっけッてなった
    * テンプレートにつかえるやつ
    
  • そのほか
    * electron で sqlite 触ろうとするとつらめな記事がそれなりに出てくる
    * universal-analytics を使って cookie に書き出して GA にあれこれするのがありがちっぽい
    * electron の awesome は便利なので、開発するときは見る
    

実際に動いているものを読むのは勉強になりますね。

あとこれを積んでいることを思い出したので、これも読みます…。

n4plus.booth.pm

github.com