JavaScript UNIXタイムスタンプと日時の相互変換

2020. 8. 4 (火) | JavaScript UNIXタイムスタンプと日時の相互変換 はコメントを受け付けていません。

以前Qiitaに投稿したもののJavaScript版です。

もちろんDateオブジェクトを利用すれば面倒な計算をすることなく相互に変換できますが、あえて自前で計算したい場合はどんな方法があるか、という例です。

UTCとの時差取得と引数省略時のデフォルト値(現在日時)取得にのみDateオブジェクトを使用していますが、それ以外のUNIX時間と日時の変換はDateオブジェクトのパーサーに頼らず自前で算出しています。

date2time()
渡した日付からUNIXタイムスタンプを返します。
引数: 年,月,日,時,分,秒,時差反映
引数を省略した場合は現在日時を使います。
時差反映は0が無し、1が有りでデフォルトは1です。

time2date()
渡したUNIXタイムスタンプから日付をオブジェクトで返します。
引数: UNIXタイムスタンプ,時差反映
引数を省略した場合は現在のUNIXタイムスタンプを使います。
時差反映は0が無し、1が有りでデフォルトは1です。

時差反映0の場合はUTCを基準とした日時での処理、1の場合は実行環境で設定された時差が反映されます。

スクリプト

使用例

タイムスタンプから年を算出する場合、目標の日数に達するまで年でループさせる力技なども考えられますが、このスクリプトでは4年、100年、400年といったグレゴリオ暦における閏年の節目の配分を調べることで年を導き出していますので、数年先、数万年先の結果を計算させたとしても負荷は変わりません。

JavaScript UNIXタイムスタンプと日時の相互変換 はコメントを受け付けていません。
PC, ソフトウェア by あけび

 PHP 祝日取得クラス

2020. 7. 10 (金) | PHP 祝日取得クラス はコメントを受け付けていません。
タグ: ,

日本の祝日を返すクラスです。

以前より個人的に使っていた処理がクラス化していなかった上、祝日定義の記述自体にも多重に三項演算子を多用していて少々メンテナンスしにくかったので、クラス化のついでにその辺も作り直しました。

春分の日及び秋分の日については簡易的な実装ですので、現在から遠い年では正しい値を返す保証はありません。

 使用例

インスタンス生成

new Holiday([$year])
year
年プロパティの初期値。省略、または0以下の値を渡した場合は現在の年で設定。

メソッド

年プロパティ変更
setYear([$year])
year
年。省略、または0以下の値を渡した場合は現在の年で設定。

1年分の祝日リストを取得
getHolidayOfYear([$year])
year
年。省略、または0以下の値を渡した場合は年プロパティの値を使用。
インスタンス内の年プロパティ変更はしません。

1か月分の祝日リストを取得
getHolidayOfMonth([$month])
month
月。省略時または範囲外の値を指定した場合は現在の月が使用されます。
年はインスタンス内の年プロパティを使用します。

戻り値のリスト形式変更
setResultType([$resultType])
resultType
戻り値の形式
0: 月、日をキーとした連想配列(デフォルト)
1: YYYY-MM-DD をキーとした連想配列

国民の休日及び振替休日の使用指定
setUseIndefiniteHoliday([$useIndefiniteHoliday])
useIndefiniteHoliday
0: 使用しない
1: 使用する(デフォルト)

 参考

「国民の祝日」について | 内閣府
昭和30年(1955年)から令和3年(2021年)国民の祝日 csv | 内閣府

PHP 祝日取得クラス はコメントを受け付けていません。
PC by あけび

 WordPressのページ出力にETagを追加する

2020. 6. 15 (月) | WordPressのページ出力にETagを追加する はコメントを受け付けていません。
タグ: ,

 ETagとは

HTTPレスポンスヘッダのひとつで、リソースの更新状況を示す識別子です。
主にブラウザのキャッシュに利用されます。

 ETagを利用したキャッシュ動作の概要

クライアント(主にWebブラウザ)が対象URLのキャッシュを持っていない場合

  • クライアントからサーバへリソース要求
  • サーバはリソースの更新状況に応じたETagをレスポンスヘッダに付加してリソースを送信
  • クライアントは受け取ったリソースを表示し、ETagが紐付けられたキャッシュを保存

クライアントがキャッシュを持っている場合

  • クライアントはキャッシュに紐付くETagIf-None-Matchとしてリクエストヘッダに付加した上で、サーバへリソース要求
  • サーバは受け取ったIf-None-Matchの内容と該当リソースのETagを比較し、一致していなければサーバ側の持つETagをレスポンスヘッダに付加してリソースを送信、一致する場合はリソースは送信せず、HTTPステータスコード304Not Modifiedを返す
  • クライアントは304 Not Modifiedを受け取った場合はキャッシュの内容を表示し、リソースであればそれを表示した上で該当するキャッシュも更新する

ブラウザキャッシュに関連するHTTPヘッダはETagの他にもいくつかありますが、ETagを利用したキャッシュは有効期限を指定するタイプのキャッシュと違い必要最小限の通信は毎回行なう反面、サーバ側でコンテンツが更新されたにもかかわらず古いキャッシュがいつまでも表示されてしまうといったトラブルも回避しやすくなります。

 WordPressをETag出力に対応させる

wp-blog-header.phpに対して以下の追記を行ないます。

動作としては、送信されるべきデータを出力バッファを介して横取りし、そのデータを元にETagを生成、クライアントからのIf-None-Matchの状況に応じて、通常通りデータ(とETag)を送るか、未更新を意味する304 Not Modifiedのみを送るかを振り分けています。

出力バッファを横取りするのにちょうどよい位置のアクションフックが見つからなかったので、プラグインではなくwp-blog-header.phpを直接書き換える方法をとっています。
WordPressの自動更新で度々上書きされるファイルでもあるので、できる限り少ない追記で対応できるようにしたつもりです。

もし他に出力バッファを扱うようなプラグイン等を利用していた場合はお互い影響してしまい正常に動作しなくなることも考えられますので、その場合はこのETag出力対応の使用は中止して下さい。

 ETagが出力されているか確認

大抵のWebブラウザにはデベロッパーツール(F12キーで起動できる場合が多い)がありますので、その中のネットワーク監視機能からそれぞれのデータのヘッダも確認することができます。
サーバから送られてくるレスポンスヘッダ内にETagのフィールドがあれば送信されてきています。

curlコマンドの-Iオプションでもレスポンスヘッダを確認できます。
WordPressはHEADリクエストされた場合は上記で変更を加えた部分に到達する前に処理が終了するようなので、-X GETオプションも付けてみてください。

一例

$ curl -I -X GET https://********.jp
HTTP/2 200
server: nginx
date: Thu, 18 Jun 2020 17:37:16 GMT
content-type: text/html; charset=UTF-8
x-powered-by: PHP/7.3.18
etag: "b3d0cb21d6686756a2f24a9311b2c467"
vary: Accept-Encoding

同じURLでありながらリクエストするたびETagが変化するようであれば、そのページには毎回変化する何かが含まれているということになります。
そのようなページであっても同じETagを出してしまってはキャッシュとして不適切ですので、それは正常な動作です。

ETagが付加されていることが確認できたら、そのETagIf-None-Matchで指定して再度リクエストしてみます。

$ curl -I -X GET -H "If-None-Match: "b3d0cb21d6686756a2f24a9311b2c467"" https://********.jp
HTTP/2 304
server: nginx
date: Thu, 18 Jun 2020 17:41:00 GMT

HTTPステータスコード304が返ってくれば、正常に動作しています。

 WordPressをETag出力に対応させたところで、どの程度恩恵があるのか

固定ページなど、長期間にわたって内容が変化しないようなページが多ければその分ネットワークトラフィックが減りますので、それなりに恩恵はあるかと思います。

表示内容に応じたETagを生成する都合上、送信する・しないに関わらずリソース(ページデータ)自体は生成しますので、サーバ側の負荷という点で見ればリソース分のトラフィックが節約できる以外はほとんど変わりはありませんが、ネットワークトラフィックの節約はとくに転送データ量に制限のあるモバイル通信などでは有用なのではないかと思います。

但し、ページ内容自体は変わっていないように見えても、そのページ内に例えばランダムに変わるおすすめページのピックアップや、コメントフォームにリロードのたびに内容の変わる認証コード系の隠しフィールドなどがあったりしてHTMLソースレベルでの変化があればETagも異なるものとなるため、その場合はキャッシュとしての動作は望めません。
ETagを使うことで恩恵のあるページがどの程度あるかを見極めながら利用を検討してください。

 参考

HTTPヘッダー | MDN
HTTPキャッシュ | MDN
ETag | MDN

WordPressのページ出力にETagを追加する はコメントを受け付けていません。
WordPress by あけび

 NASのバックアップ対象ディレクトリをinotifyで監視して更新されたディレクトリのみをrsyncでミラーリング

2020. 4. 21 (火) | NASのバックアップ対象ディレクトリをinotifyで監視して更新されたディレクトリのみをrsyncでミラーリング はコメントを受け付けていません。
タグ: , , ,
前回書いたミラーリングと世代管理バックアップの2系統のスクリプトのうち、ミラーリングのほうのスクリプトについてパフォーマンスアップの修正を行ないました。

前回のスクリプトでは大まかな流れとしてduコマンドの結果を元に更新対象ディレクトリを絞り込んでrsyncに渡すという動作を行なっていましたが、監視対象内のサブディレクトリ数が多くなるとduコマンドの実行時間もそれなりにかかるようになるので、この部分をinotifywaitコマンドでの監視に置き換えています。

inotifywaitを使えるよう準備

inotify-toolsがインストールされていない場合inotifywaitコマンドも使えませんので、その場合はまずinotify-toolsをインストールします。

inotify-toolsをインストール(Debian系の場合)

$ sudo apt install inotify-tools

inotifywaitで監視可能な対象数はデフォルトで8192になっているかと思いますが、NAS全体を監視対象にしようとするとサブディレクトリ数も多くなり8192では不足する場合もままありますので、環境に合わせてこの設定を増やしておきます。

設定値の確認

$ cat /proc/sys/fs/inotify/max_user_watches

この設定は再起動すると初期値に戻ってしまいますので、起動時に自動で設定されるようにしておきます。
いくつか方法はありますが、私はrc.localに追記しました。

$ sudo nano /etc/rc.local

以下を追記

sysctl fs.inotify.max_user_watches=262144

以降は前回と同じ方法でmirroring.phpの実行設定をすれば完了です。

スクリプト

ディレクトリの更新監視にinotifywaitを利用してはいますが、更新があった場合に自動的にmirroring.phpが実行されるわけではなくmirroring.phpはこれまで通りcronで定期的に実行し、スクリプト内でinotifywaitのログを参照することでその間に更新のあった監視対象内のサブディレクトリを取得してrsyncに渡すという動作になっています。

ここまで書いておいて何ですが、inotifyで監視してrsyncで同期という流れはLsyncdと似たようなことをしているわけなので、人によっては素直にLsyncdを導入したほうが楽かもしれません。

NASのバックアップ対象ディレクトリをinotifyで監視して更新されたディレクトリのみをrsyncでミラーリング はコメントを受け付けていません。
PC, ソフトウェア by あけび

 rsyncでNASのバックアップ(ミラーリングと世代管理バックアップ分離版)

2020. 4. 7 (火) | rsyncでNASのバックアップ(ミラーリングと世代管理バックアップ分離版) はコメントを受け付けていません。

今回もまた前回と同じような内容ですが、しばらく使っていると “こうしたほうが使いやすそう” と感じる部分もいくつか見えてくるのでその都度反映させていたりします。

LinuxディストリビューションとSambaで構築したNASにネットワーク共有用とバックアップ用それぞれ独立したHDDを載せて、以下のような構成で運用しているものに対してミラーリング及び世代管理バックアップを行う前提で記述しています。

NAS用ドライブ
ルート直下に
/data/ … ネットワークドライブ用
というディレクトリを作成。
これをマウントポイント
/home/nas/
にマウントしてあり、
/home/nas/data/
をsambaで共有ディレクトリに設定することでNASのネットワークドライブとして使用。
バックアップ用ドライブ
ルート直下に
/data/ … ミラーリング用
/generation/ … 世代管理バックアップ用
というディレクトリを作成。
これをマウントポイント
/home/nas_backup/
にマウントすることで、
/home/nas_backup/data/
を/home/nas/data/のミラーリング先、
/home/nas_backup/generation/
を/home/nas_backup/data/の世代バックアップ先としています。
 

図にするとこんなイメージになります。

 

mirroring.php
NAS共有ディレクトリをバックアップ元として、バックアップ先ドライブに対してrsyncの--deleteオプションを使用したミラーリングを行うスクリプトです。

バックアップ元ディスク容量が前回実行時から変化していなければrsyncは行わず終了するようにしてありますので頻繁に実行しても極端に負荷が高くなることは無いとは思いますが、その辺りは環境に合わせて加減してください。
容量チェックはdfコマンドを使用したものでファイル名の変更や小サイズの変更などブロックサイズの変化しない更新は察知できませんので、前回実行から1時間以上経過していたらバックアップ元ディスク容量が変化していなくてもrsyncを実行するようにしています。

主な設定項目
// ミラーリング元ディレクトリ
define(‘SOURCE_DIR’, ‘/home/nas/data/’);

ミラーリング元となるディレクトリを指定。

// ミラーリング先ディレクトリ
define(‘BACKUP_DIR’, ‘/home/nas_backup/data/’);

ミラーリング先となるディレクトリを指定。
こちらは先頭に「ユーザーアカウント@ホスト名:」等を含めたリモートでの指定も可能ですが、cronでの自動実行時にはリモートへのログイン時にパスワード入力待ちが発生しないようパスワード無しでの鍵認証ログインができるよう適宜設定しておく必要があります。

 

generation.php
ミラーリングされたディレクトリを元に、世代管理用ディレクトリに対してrsyncの--link-destオプションを使用したバックアップを行うスクリプトです。
バックアップ用ドライブがNAS本体とは別のリモートにある場合はこのスクリプトもリモート側へ設置します。

実行日時を名前としたディレクトリを作成し、その中にその時点のバックアップを残していきます。
rsyncの–link-destオプションを使うことで新規追加や変化のあったファイルのみが実体として保存され、それ以外のファイルはハードリンクが追加されるだけですので、ディスク容量消費や処理時間は増分バックアップと同程度でありながら作成されるバックアップはそれぞれがフルバックアップ相当になるという特徴があります。
1日以上経過したバックアップはその日の最終版のみ残して削除、1か月以上経過したバックアップはその月の最終版を残して削除、THRESHOLDで指定したディスク使用量に達した場合は下回るまで古いバックアップから削除といった処理もこちらのスクリプトで行なっています。

ハードリンクを有効に活用するため–link-destには1世代前のバックアップを指定するのが一般的ですが、今回の場合$sourceDir自身が既にミラーリングされたバックアップの一部なのでこちらを–link-destに指定しています。
こうすることで、容量の節約と同時に処理速度の短縮も図れます。

主な設定項目
// バックアップ元ディレクトリ
define(‘SOURCE_DIR’, ‘/home/nas_backup/data/’);

mirroring.phpでミラーリング先となったディレクトリを指定します。

// バックアップ先ディレクトリ
define(‘BACKUP_DIR’, ‘/home/nas_backup/generation/’);

世代管理バックアップ保存先を指定します。
このディレクトリの下に
YYYY-MM-DD_HHMM
形式でディレクトリが作成され、その中に各世代のバックアップが保存されていきます。
rsyncの--link-destオプションを使用し変更のないファイルは実体ではなくハードリンクが作成されますので、必要以上にディスク容量を消費しません。

// バックアップ世代数
define(‘BACKUP_GENERATION’, 200);

保存したい世代数を指定します。
世代バックアップ数がこの値を超えたら古いバックアップから削除されますが、間引き処理やディスク容量による削除処理の兼ね合いで、ここで指定した数に達する前に削除が行なわれる場合もあります。

// 古いバックアップを削除するディスク容量閾値(%)
// 0の場合はディスク容量のチェックは行いません
define(‘THRESHOLD’, 95);

dfコマンドでバックアップ先のディスク使用量(%)をチェックし、この値に達していたら値を下回るまで古いバックアップから順に削除を行います。
0では削除処理を行わなくなりますが、バックアップ先の空き容量が無くてもrsyncの実行を抑制する等の処理は行いません。

crontab設定例

# rsync mirroring
* * * * * php /スクリプト設置パス/mirroring.php &> /dev/null
* * * * * sleep 30; php /スクリプト設置パス/mirroring.php &> /dev/null
# rsync generation backup
0 */6 * * * php /スクリプト設置パス/generation.php &> /dev/null

上記の例では前半ブロックで30秒ごとのミラーリングを、後半ブロックで6時間ごとに世代管理バックアップを行なっています。

rsyncでNASのバックアップ(ミラーリングと世代管理バックアップ分離版) はコメントを受け付けていません。
PC, ソフトウェア by あけび