HRR Co., Ltd.

技術的な記録を残していくことを目的としています。1次情報を大事にしています。

VirtualBox + CentOS7 + Nginx + PHP-FPM でPHPを動かすまで

はじめに

登場人物がインストール済みで、設定周りをどうするか、のメモになります。
というわけで、前提条件が結構あります。

  • PHPはインストール済み(記事を書いたものの保存し忘れでサヨウナラ…)
  • PHP-FPMもインストール済み
  • Nginxもインストール済み
  • 前回の記事の続きみたいな感じです。

hrroct.hatenablog.com

ゴール

http://localhost:8080/index.php にアクセスして、index.phpに書いたphpinfo()の結果が表示されるところまで。

やったこと

設定ファイルを変更する前にバックアップを取ることをオススメします。

PHP-FPMの設定

# vi /etc/php-fpm.d/www.conf

Nginxで動かすので、userとgroupの変更を行います。

; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
;       will be used.
; RPM: apache user chosen to provide access to the same directories as httpd
;user = apache
user = nginx
; RPM: Keep a group allowed to write in log dir.
;group = apache
group = nginx

さらに今回の場合、ブラウザからアクセスするときにポート番号を8080にしているので、 listenのポート番号を変更します。

; The address on which to accept FastCGI requests.
; Valid syntaxes are:
;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific IPv4 address on
;                            a specific port;
;   '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
;                            a specific port;
;   'port'                 - to listen on a TCP socket to all addresses
;                            (IPv6 and IPv4-mapped) on a specific port;
;   '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
;listen = 127.0.0.1:9000
listen = 127.0.0.1:8080

忘れずに再起動も行います。

# systemctl restart php-fpm

Nginxの設定

まずrootのindexファイルとして、index.phpを許可します。
rootも必要に応じて変更しましょう。

# vi /etc/nginx/conf.d/default.conf

  location / {
      root   /usr/share/nginx/html;
-     index  index.html index.htm;
+     index  index.html index.htm index.php;
  }

さらに、rootやポート番号、fastcgi_paramを書き換えます。

- #location ~ \.php$ {
- #    root           html;
- #    fastcgi_pass   127.0.0.1:9000;
- #    fastcgi_index  index.php;
- #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
- #    include        fastcgi_params;
- #}
+ location ~ \.php$ {
+     root           /usr/share/nginx/html;
+     fastcgi_pass   127.0.0.1:8080;
+     fastcgi_index  index.php;
+     fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
+     include        fastcgi_params;
+ }

Nginxの再起動も忘れずに。

# systemctl restart nginx

SELinuxの設定

私の場合はこれも必要でした。

# vi /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
#SELINUX=enforcing
SELINUX=disabled

index.phpを作成する

# vi /usr/share/nginx/html/index.php
<?php
phpinfo();

設定は以上です。

確認

…する前に、ログファイルを監視することをオススメします。
うまくいかない場合、何かしらログに残っているはずです。

# tail -f /var/log/php-fpm/error.log /var/log/nginx/{access,error}.log

エラーコードやエラー内容で検索すれば、きっと解決できることでしょう。

http://localhost:8080/index.php
にアクセスして、インストールされたPHPの情報が表示されればOKです。

最後に

今や検索すれば、設定に困ることはなくなりましたね。
似たようなことをやっている方は、必ずいらっしゃるものですから。

以上でした!

VirtualBox + CentOS 7 + nginxでブラウザからアクセス

はじめに

仮想環境へWebサーバーであるnginx(エンジンエックス)の導入、そしてブラウザからのアクセスまでを行います。

VirtualBoxCentOSの部分は過去記事をご参照ください。
hrroct.hatenablog.com

手順

とりあえずyum update

ちなみにyumとは。

Yellowdog Updater Modified
"LinuxRPM Package Managerのパッケージを管理するメタパッケージ管理システムである。"

Yellowdog Updater Modified - Wikipedia

今回は、何かを始める前に、各種アプリケーションをupdateしましょう、くらいの意味合いです。
基本的にrootユーザーで作業していきます。

yum update

nginx導入

nginxとは。

nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server, originally written by Igor Sysoev.

nginx

Apacheを使っている方はまだ多いと思いますが、非同期のイベント駆動のアプローチをするnginxはApacheと比べて

高負荷下において、より予測可能なパフォーマンスを提供すると考えられている

nginx - Wikipedia
とのことです。

今回、nginxの安定版を使用しようと思います。
やり方は同じく公式サイトに書いてあります。
nginx: Linux packages

ただし、"OS"を"centos"に、"OSRELEASE"を"7"に書き換える必要があります。

vi /etc/yum.repos.d/nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

nginx用のリポジトリ設定ができたので、あとは(CentOS的に)普通にインストールします。

yum -y --enablerepo=nginx install nginx
nginx -v
# nginx version: nginx/1.14.0

バージョン情報が表示されれば、無事インストールできています。

nginx起動

起動と、ついでに自動起動の設定も行っておきます。

# 起動
sudo systemctl start nginx
# 自動起動設定
sudo systemctl enable nginx
# ステータス確認
sudo systemctl status nginx

statusは複数行表示されますが、3行目あたりに

   Active: active (running)

って緑色で表示されていればOKです。

この時点で、

curl localhost

をすれば、ドキュメントルートにあるindex.htmlファイルの中身が返ってくると思います。
ただし、まだブラウザを介してのアクセスはできません。
CentOSファイアウォールの設定と、ポートフォワーディングの設定が必要になります。

ファイアウォールの設定(httpの許可)

これはCentOS側の設定になります。

firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --reload

http(ポート80)を許可してあげればOKです。

ポートフォワーディングの設定

仮想マシンはデフォルトでは閉じた世界になっているので、80番ポートを開けただけでは、外の世界からhttp://localhost/でのアクセスはできません。

そこで以前の記事にも書いたポートフォワーディングの設定を行います。
詳細は以前の記事を見ていただくとして…

hrroct.hatenablog.com

f:id:hrroct:20180715212131p:plain
今回は、httpを追加します。
ホストポートの"8080"は、空いていれば何でもいいです。
そして、CentOSを再起動します。

ホスト側からブラウザでアクセスしてみる

http://localhost:8080/
にアクセスすれば、nginxの初期ページが表示されるはずです。

f:id:hrroct:20180715213433p:plain

さいごに

ただアクセスできるようにしただけなので、これからまだnginxについては設定が必要になります。
長くなるので、それはまたの機会に…。

以上でした!

素のJavaScriptでAJAX処理を書くには?

はじめに

素のJavaScriptで、AJAXの通信部分の処理をどう書くのか?
Vanilla JSにあるサンプルを解読してみました。

jQueryにどっぷりハマっている方向けかも知れません。

対象のコードはこちら

Vanilla JS

こちらからお借りしました。

var r = new XMLHttpRequest();
r.open("POST", "path/to/api", true);
r.onreadystatechange = function () {
  if (r.readyState != 4 || r.status != 200) return;
  alert("Success: " + r.responseText);
};
r.send("banana=yellow");

上から読んでいきます

まず XMLHttpRequest オブジェクトから。

developer.mozilla.org

  • XHRなどと略されるオブジェクト。AJAXでよく使われます。
  • サーバーとの通信という意味では、選択肢はこれに限りません。
  • 名前に反して、XMLじゃなくても、httpプロトコル以外も対応しています。

使い方ですが…
まずコンストラクタ XMLHttpRequest() を実行して、初期化する必要があります。

var r = new XMLHttpRequest();

r.open() はリクエストの初期化を行います。
developer.mozilla.org

var r = new XMLHttpRequest();
r.open("POST", "path/to/api", true);

引数は前から順にメソッド、URL、非同期/同期 (true/false) です。
同期通信は多くのブラウザで非推奨とされているとのこと。

var r = new XMLHttpRequest();
r.open("POST", "path/to/api", true);
r.onreadystatechange = function () {
  if (r.readyState != 4 || r.status != 200) return;
  alert("Success: " + r.responseText);
};

r.onreadystatechange は、readystatechange イベント ( XMLHttpRequest の readyState 属性が変化)が発火するたびに呼ばれる EventHandler です。
構文はこんな感じ。

XMLHttpRequest.onreadystatechange = callback;

イベントが発火すると、callback に指定した関数が実行されます。

ではこの readyState 属性が何者かというと…
developer.mozilla.org

状態 説明
0 UNSENT クライアントは作成済み。open() はまだ呼ばれていない。
1 OPENED open() が呼び出し済み。
2 HEADERS_RECEIVED send() が呼び出し済みで、ヘッダーとステータスが利用可能。
3 LOADING ダウンロード中。responseText には部分データが入っている。
4 DONE 操作が完了した。
var r = new XMLHttpRequest();
r.open("POST", "path/to/api", true);
r.onreadystatechange = function () {
  if (r.readyState != 4 || r.status != 200) return;
  alert("Success: " + r.responseText);
};

4の状態は成否に関わらず処理が終わってます。
status 属性はHTTPステータスコードです。
つまり、処理が正常に終了したときだけ、レスポンスを alert 関数で出力するようになっています。

callback 関数の定義が終わったら、あとは r.send() でデータを送信します。
送ったあとは、サーバー側での処理を経て、callback 関数に落ち着くというわけですね。

var r = new XMLHttpRequest();
r.open("POST", "path/to/api", true);
r.onreadystatechange = function () {
  if (r.readyState != 4 || r.status != 200) return;
  alert("Success: " + r.responseText);
};
r.send("banana=yellow");

さいごに

JavaScript はいろんなフレームワークやライブラリが出ておりますが、素の仕組みを知っておくことも大事ですよね。
と思ったのが今回のきっかけでした。
mozilla のサイトにマニュアルがあるので、調べるのに便利ですね。

また似たような記事を書くかも知れません。
以上でした!

Python3でWebサイトのスクレイピングをCygwinから

はじめに

特定のWebサイトの情報抜き出しを、Python3でやってみました。
Googleクローラーのようなことをやるのは大変です。
でも、特定のサイトの特定の情報なら、そんなに難しくはないので、ぜひ挑戦してみることをオススメします。

ただし、相手のサイトに迷惑をかけるようなことだけはNGです。
過去捕まった人が出た事例もありますので、ご注意を…。

準備から

まずはPython本体

まずPython3を入れるところから…
Cygwin使ってます。

$ apt-cyg searchall python3
$ apt-cyg install python3

searchallで探すとすぐ見つかりますので、インストールは簡単です。
ただし、"python3"というファイル名になっているので、シムリンクを作成して、"python"で実行できるようにしておきます。
これはお好みでどうぞ。

$ which python3
/usr/bin/python3
$ ln -s /usr/bin/python3 /usr/bin/python
$ python --version
Python 3.6.3

パッケージ管理システムのインストール

pip というPythonのパッケージ管理システムを入れます。

$ apt-cyg searchall pip
$ apt-cyg install python3-pip

注意点として、今回入れるのはPython3用のpipであること。
"python3-pip"を指定しましょう。
install後は"pip3"になることも要注意。

$ which pip3
/usr/bin/pip3
$ ln -s /usr/bin/pip3 /usr/bin/pip
$ pip --version
pip 9.0.1 from /usr/lib/python3.6/site-packages (python 3.6)

こちらもおまけですが、シムリンクを作成してみました。

スクレイピングに便利なパッケージを入れる

Beautiful Soupを使います。
Beautiful Soup Documentation — Beautiful Soup 4.4.0 documentation
XMLやHTMLからデータを取得するためのPythonライブラリ(意訳)」とのこと。
そしてBeautiful Soup 4が最新のようです。

私は普段PHPを使いますが、PHPでは取得したHTMLからの抽出が大変なので、この手のライブラリが充実しているPythonはいいですね。

$ pip search beautifulsoup4
$ pip install beautifulsoup4
Collecting beautifulsoup4
  Downloading https://files.pythonhosted.org/packages/9e/d4/10f46e5cfac773e22707237bfcd51bbffeaf0a576b0a847ec7ab15bd7ace/beautifulsoup4-4.6.0-py3-none-any.whl (86kB)
    100% |????????????????????????????????| 92kB 1.0MB/s
Installing collected packages: beautifulsoup4
Successfully installed beautifulsoup4-4.6.0
You are using pip version 9.0.1, however version 10.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

何やらpipのバージョンが古いと言われてますので、言われたとおり

pip install --upgrade pip

を実行しておくことをオススメします。

ようやくコーディング

特定のサイトを指定するわけにもいかないので、サンプルを提示しようと思います。

# coding: UTF-8

# Webサイトへのアクセスに使うライブラリをimport
import urllib.request
from bs4 import BeautifulSoup

url = "対象のURL"

try:
    # URLにアクセス
    html = urllib.request.urlopen(url)
except:
    print('Cannot open the url.')

try:
    # HTMLのパース
    soup = BeautifulSoup(html, "html.parser")
except:
    print('Cannnot read the html data.')

# HTMLを解析、欲しいデータを持ってくる
targets = soup.select('#contents ul li a')

# タグの中の文字列を取得する
for target in targets:
    text = target.get_text()
    print(text)

HTMLの中から特定のタグを探す手段はたくさんあります。
今回は比較的わかりやすいと思われるCSSセレクタを使いました。

タグの中の文字列を取得する手段も、複数用意されています。
詳細はマニュアルを参照のこと。
Beautiful Soup Documentation — Beautiful Soup 4.4.0 documentation

最後に

今回はサイトから特定のデータを取得することが目的だったので、あまりBeautiful Soup自体の深掘りはしませんでした。
対象によっては異なるメソッドを使うほうが効率がよかったりするでしょうから、ぜひマニュアルをご一読くださいませ。

以上でした。

GAS(JavaScript)でよく使う日付フォーマット処理を書きました

はじめに

最近、GAS(Google Apps Script)を使っているのですが、ほぼJavaScriptでして、日付の扱いがちょっと面倒です。
そこで今回、日付をいろんな形式で出力できるフォーマッターを作成しましたので、共有します。

ソースコード

/**
 * 日付のフォーマッター
 * @param {date}   date   dateオブジェクト
 * @param {string} format 書式フォーマット
 */
function formatDate(date, format) {
  format = format.replace(/yyyy/g, date.getFullYear());
  format = format.replace(/mm/g, ('0' + (date.getMonth() + 1)).slice(-2));
  format = format.replace(/dd/g, ('0' + date.getDate()).slice(-2));
  format = format.replace(/aaa/g, ['日','月','火','水','木','金','土'][date.getDay()])
  format = format.replace(/AAA/g, ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][date.getDay()])
  format = format.replace(/HH/g, ('0' + date.getHours()).slice(-2));
  format = format.replace(/MM/g, ('0' + date.getMinutes()).slice(-2));
  format = format.replace(/ss/g, ('0' + date.getSeconds()).slice(-2));
  format = format.replace(/SSS/g, ('00' + date.getMilliseconds()).slice(-3));

  return format;
};

これをテスト実行してみます。

/**
 * テスト実行
 */
function sample() {
  var dateObj = new Date();
  Logger.log(formatDate(dateObj, 'yyyy/mm/dd(AAA) HH:MM:ss.SSS'));
}

このsampleを実行すると、こんな出力になります。
スクリプトエディタの「表示」→「ログ」、またはCtrl + Enterでも表示できます。

[18-06-10 08:33:00:835 JST] 2018/06/10(Sun) 08:33:00.833

解説

メインの方

date.getMonth() 

は 0 - 11 の数字が返るので、+1しなくてはなりません。

date.getDay()

は曜日を取得しますが、こちらは0 - 6 (日、月、…土)で返るので、こちらも変換しなくてはなりません。
['日','月','火','水','木','金','土']という配列を作って、要素部分に date.getDay() を当てはめれば、曜日が取得できます。

もう少し丁寧に書くならこんな感じです。

var dayOfWeekList = ['日','月','火','水','木','金','土'];
var dayOfWeek = dayOfWeekList[date.getDay()];

テスト実行の方

new Date();

は引数なしなので、今現在の日時になります。

Logger.log();

を実行することで、スクリプトエディタの「表示」→「ログ」にログが残ります。
Ctrl + Enterでも表示できます。

formatDate(dateObj, 'yyyy/mm/dd(AAA) HH:MM:ss.SSS')

formatDate関数は、ただ文字列を置換しているだけなので、取得したい情報を文字列で指定するだけです。
日本語風に取得したければ、こんな感じでしょうか。

formatDate(dateObj, 'yyyy年mm月dd日(aaa)')

おわりに

JavaScriptで日付の処理を書くときに、毎回忘れているので、まとめることにしました。
記事にしたことで、忘れないといいな…

以上でした。