目次

36協定チェック

MFクラウド勤怠の「月別データ」xlsxを読み込み、36協定のチェック結果を出力する社内ツール。 PHP標準機能のみで動作し、外部ライブラリ・データベース不要。

⚠ 取り扱い注意

従業員の勤怠情報を扱います。

* このリポジトリはPrivateのまま運用してください * `master.csv`(氏名を含む)と `.htpasswd` は `.gitignore` で除外済み。コミットしないでください * 公開ディレクトリに置く場合は、必ずBasic認証またはIP制限をかけてください

セットアップ

1. サーバーに配置

/36kyotei/
  ├─ index.php
  ├─ master.csv     ← サーバー上で管理(Git管理外)
  ├─ .htaccess      ← アクセス制限
  └─ .htpasswd

`genpass.php` をアップロードしてブラウザで開き、ID・パスワードを入力すると `.htaccess` と `.htpasswd` を自動生成します。

設定後は genpass.php と check.php を削除してください。

エックスサーバーの場合は、サーバーパネルの「アクセス制限」機能を使うほうが確実です。

2. 所属係マスタ

`master.csv.example` をコピーして `master.csv` を作り、サーバーに置きます。

画面からアップロードすることもできます(「サーバーに保存して次回から使う」にチェックすると保存されます)。

氏名,所属部,所属係
山田 太郎,第一事業部,設計1係

文字コードは自動判定(UTF-8 / UTF-8 BOM / Shift_JIS)。

Excelで編集して保存したCSVがそのまま使えます。

`master.csv` が無い場合は、勤怠データの「役職」列(例:`設計1係 担当`)から係名を自動判定します。

GitHub Actions で自動デプロイ

`main` にプッシュすると、PHPの構文チェックを通してから rsync over SSH でサーバーに反映します。

Secrets の登録

Settings → Secrets and variables → Actions → New repository secret で登録します。

Secret名 内容
`SSH_HOST` ホスト名 `sv637.xbiz.ne.jp`
`SSH_USER` サーバーID `colorspro`
`SSH_KEY` 秘密鍵の全文(`—–BEGIN` 〜 `—–END` を含む)
`DEPLOY_PATH` 配置先の絶対パス(末尾スラッシュ必須 `/home/colorspro/example.co.jp/public_html/overtime-check/`
`SSH_PORT` 任意。未設定なら `10022`

SSH鍵の作り方

エックスサーバーは公開鍵認証のみ(パスワード認証は不可)、ポートは 10022 です。

* サーバーパネル →「SSH設定」→「+公開鍵を登録」 * ラベルを入力し「登録して秘密鍵をダウンロードする」 * ダウンロードした `.key` をテキストエディタで開き、全文をコピーして `SSH_KEY` に貼り付け

秘密鍵はGitHubのSecrets欄以外に貼り付けないでください。 メールやチャットに載せた場合は、必ず鍵を再発行してください。

接続確認

登録前に手元で確認できます。

# Mac / Windows(PowerShell) 共通
ssh -i "秘密鍵のパス" -p 10022 サーバーID@ホスト名 "pwd; ls -d 配置先の相対パス"

`/home/サーバーID` とフォルダ名が返ってくれば、`DEPLOY_PATH` はその2つをつなげたものになります。

デプロイされないファイル

`master.csv` `.htaccess` `.htpasswd` `data/` `*.xlsx` および Docker・CI関連ファイルは除外されます。

`–delete` は使っていないため、サーバー上のファイルが自動デプロイで消えることはありません。

ワークフローの流れ

構文チェック → SSH設定の確認 → SSH鍵を配置 → 接続テスト → rsyncで同期 → 鍵の後片付け

Secretsが未登録の場合は失敗せず、警告を出してスキップします。

`DEPLOY_PATH` が絶対パスでない、または末尾スラッシュが無い場合は転送前にエラーで停止します。

手動実行

Actions タブ → Deploy to Xserver → Run workflow

ローカル環境の起動

Windows・Mac のどちらでも、スクリプトを1つ実行するだけで起動します。

中身は同じで、動くOSが違うだけです。

やること Windows Mac
ローカル起動 `setup.bat` をダブルクリック `bash setup.sh`
停止 `stop.bat` `bash stop.sh`
ログを見る `logs.bat` `bash logs.sh`
社内LAN公開 `lan-access.bat` `bash lan-access.sh`
サーバーから取り込む `pull-remote.bat` `bash pull-remote.sh`
手動デプロイ `deploy.bat` `bash deploy.sh`

Macでは `bash` を付けて実行してください。

Windowsで作られたファイルは実行権限が付かないため、`./setup.sh` だと `Permission denied` になることがあります。

気になる場合は一度だけ `chmod +x *.sh` を実行すれば `./setup.sh` でも動きます。

事前に必要なもの

# 1) Docker Desktop を公式サイトからインストール
#    ★ Intel版(amd64) と Apple Silicon版(arm64) でインストーラが別です
#      uname -m  →  x86_64 なら Intel / arm64 なら Apple Silicon
#    https://www.docker.com/products/docker-desktop/
 
# 2) Mac で Homebrew が未導入なら https://brew.sh/
 
# 3) 以下を実行
 
brew install git 

初回セットアップ

Mac

mkdir -p ~/Docker-work && cd ~/Docker-work
git clone https://github.com/Colors-ryomorita/36kyotei.git
cd 36kyotei
cp .env.example .env
bash setup.sh

Windows(PowerShell)

cd C:\Docker-work
git clone https://github.com/Colors-ryomorita/36kyotei.git
cd 36kyotei
copy .env.example .env
.\setup.bat

`setup` はDockerの起動確認 → `.env` の作成 → ビルド → 起動確認までを行い、成功するとブラウザが自動で開きます。

http://localhost:8080

.env の設定

`deploy` と `pull-remote` を使う場合だけ編集します。

ローカル起動だけなら初期値のままで動きます。

APP_PORT=8080                  # ポートを変えたいとき
 
SSH_HOST=sv637.xbiz.ne.jp      # サーバーパネル →「サーバー情報」
SSH_USER=colorspro             # サーバーID
SSH_PORT=10022
SSH_KEY=docker/ssh/xserver.key # 秘密鍵の置き場所
DEPLOY_PATH=/home/colorspro/example.co.jp/public_html/overtime-check/ 

`.env` と秘密鍵は `.gitignore` で除外済みです。

コミットされません。

特徴

* ソースをマウントしているので、index.php を編集して保存 → ブラウザ再読み込みだけで反映されます。ビルドし直す必要はありません * `display_errors = On` なので、PHPのエラーが画面にそのまま表示されます * `data/` フォルダに勤怠xlsxを置くと、画面のプルダウンから選べます * `.htaccess` が有効(`AllowOverride All`)なので、Basic認証の動作も確認できます

チップの種類について(Intel / Apple Silicon)

どちらでもそのまま動きます。

`docker-compose.yml` やスクリプトを書き換える必要はありません。

ただし Docker Desktop のインストーラだけは別物なので、ここを間違えないでください。

uname -m        # x86_64 → Intel / arm64 → Apple Silicon
Mac ダウンロードするもの
Intel チップ Docker Desktop for Mac with Intel chip(amd64)
Apple Silicon(M1〜M4) Docker Desktop for Mac with Apple silicon(arm64)

使用しているイメージは両方のCPUに対応しているので、`platform:` の指定は不要です。

イメージ Intel (amd64) Apple Silicon (arm64)
`php:8.2-apache`

Intel Mac で気をつけること

内容
macOSのバージョン Docker Desktop がサポートするのは最新+その前2つのメジャーバージョンまで。古いIntel Macで macOS を上げられない場合、最新版の Docker Desktop は入りません(旧バージョンを探すことになります)
メモリ 最低2GB。Settings > Resources で割り当てを確認してください(このツールはPHP+Apacheの1コンテナのみなので軽量です)
Homebrewの場所 Intelは `/usr/local`、Apple Siliconは `/opt/homebrew`。`brew install` のあとに `command not found` が出たら下のコマンドを `~/.zshrc` に追記
Rosetta 2 不要です(Intelネイティブのため)
速度 Apple Silicon より遅いので、後述の VirtioFS の設定を推奨します
# Intel Mac で git / gh が見つからない場合
echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zshrc
source ~/.zshrc

Apple Silicon で気をつけること

特別な設定は要りません。

Rosetta 2 は必須ではありませんが、一部のコマンドラインツールが必要とするため入れておくと無難です。

softwareupdate --install-rosetta

動作が遅いと感じたら

Docker Desktop > Settings > General で VirtioFS が選ばれているか確認してください(macOSのファイル共有はこれが一番速いです)。

ポート8080が使われている場合

`.env` の `APP_PORT` を変更して `setup` を実行し直してください。

APP_PORT=8081

使用中のプロセスは Mac なら `lsof -i :8080`、Windows なら `netstat -ano | findstr :8080` で確認できます。

SSH鍵を置いたとき

Macでは権限を絞らないと ssh が鍵を読み込みません。

chmod 600 docker/ssh/xserver.key

`setup.sh` と `deploy.sh` は自動で直しますが、手で ssh を叩くときは必要です。

フォルダ構成

36kyotei/
  ├─ index.php              ← 本体
  ├─ check.php              ← 環境チェック(本番では削除)
  ├─ genpass.php            ← 認証ファイル生成(本番では削除)
  ├─ master.csv             ← 所属係マスタ。実名のためGit管理外
  ├─ master.csv.example
  ├─ .env                   ← 環境設定。Git管理外
  ├─ .env.example
  ├─ data/                  ← 勤怠xlsxの置き場。Git管理外
  ├─ docker/
  │    ├─ php.ini
  │    └─ ssh/              ← 秘密鍵の置き場。Git管理外
  ├─ Dockerfile
  ├─ docker-compose.yml
  ├─ setup.bat / setup.sh
  ├─ stop.bat / stop.sh
  ├─ logs.bat / logs.sh
  ├─ lan-access.bat / lan-access.sh
  ├─ pull-remote.bat / pull-remote.sh
  ├─ deploy.bat / deploy.sh
  └─ .github/workflows/
       ├─ ci.yml            ← 構文チェック・起動確認・Dockerビルド
       └─ deploy.yml        ← SSH(rsync)自動デプロイ

動作環境の差分

Docker(ローカル) エックスサーバー
PHP 8.2 サーバーパネルで選択
エラー表示 画面に出る 通常は出ない
upload_max_filesize 16M 初期値は環境による

ローカルで動けばサーバーでも動きます。

サーバーだけで失敗する場合は、PHPバージョンかアップロード上限が原因のことがほとんどです。

`check.php` で確認してください。

CI(GitHub Actions)

プッシュのたびに自動で検証します。

ジョブ 内容
構文チェック 全 `.php` に対して `php -l`
スモークテスト 実際に起動してHTTP 200を確認。Parse error / Fatal error / Warning が出ていないかも検査
バリデーション確認 月次基本時間を空でPOSTし、必須チェックが効くか確認
Dockerビルド確認 イメージがビルドできるか
機密情報チェック `master.csv` `.htpasswd` `.htaccess` `data/` `*.xlsx` がコミットされていないか

いずれかが失敗するとデプロイされません。

使い方

MFクラウド勤怠からのエクスポート

全権管理者メニュー > 連携 > エクスポート > 月別データ

設定項目 当月チェック 前月チェック
対象年月 単月(当月) 複数月(前月を最終月とする直近6か月)
出力単位 従業員 > 全て 従業員 > 全て
時間フォーマット 10進数(切り上げ) 10進数(切り上げ)
実質労働時間 含めない 含めない
年月を含める 含める
形式 xlsx xlsx

時間フォーマットは必ず10進数にしてください。

60進数(`1.30`=1時間30分)のままだと判定と割り算が狂います。

読み込み時に自動換算しますが、MF側の設定が確実です。

ファイル名は変更しないでください。

単月出力には対象年月の列が無いため、ファイル名から対象月を判定しています。

出力

モード 判定 内容
前月(対象月が過去) 実績 45時間以上の対象者/複数月平均80時間超/45時間超3回以上/通算バランス
当月(対象月が今月) 月末見込み 見込み30時間以上の対象者

共通で「月別 超過者一覧」(月次基本時間との比較)を出力します。

計算仕様

判定基準

残業時間または月末見込み 判定
80時間以上 危険
45〜80時間未満 36協定超過
30〜45時間未満 要注意
20〜30時間未満 要監視
20時間未満 問題なし

法令との対応

基準 対象範囲 使用する値
月45時間・年360時間 時間外労働のみ `法定外時間(平日・所定休日)`
2〜6か月平均で月80時間以内 時間外労働+休日労働 残業時間+休日稼働時間
月45時間超は年6回まで 時間外労働のみ `法定外時間(平日・所定休日)`

当月の月末見込み

見込みA = 残業時間 ÷ 経過営業日数 × 所定労働日数
見込みB =(総労働時間 - 所定時間)÷ 経過営業日数 × 所定労働日数
判定には A と B の大きいほうを使用(安全側)

見込みBを併用するのは、法定外時間が週単位で確定するため月初〜週の途中では0のままになるためです。

総労働時間-所定時間は初日から反応します。

通算バランス(帳尻)

各月の「総労働時間 - 月次基本時間」を積み上げた累計。

ある月に超過しても翌月に下回れば累計は戻ります。

集計途中の当月は累計から自動的に除外されます。

含めると全員が大きくマイナスになり、帳尻が合って見えるためです。

月次基本時間の初期値は `MONTHLY_BASE_DEFAULT`(162.67時間=年間所定労働時間1952時間 ÷ 12)。

画面で変更できます。

カスタマイズ(index.php 冒頭の定数)

定数 内容 初期値
`EXCLUDE_TITLES` 集計対象外の役職 代表取締役・取締役・監査役・役員・部長
`TH_DANGER` / `TH_OVER` / `TH_WATCH` / `TH_MONITOR` 判定しきい値 80 / 45 / 30 / 20
`LIST_MIN_ACTUAL` 前月モードの一覧下限 45
`LIST_MIN_FORECAST` 当月モードの一覧下限 30
`MONTHLY_BASE_DEFAULT` 月次基本時間の初期値 162.67
`MASTER_CSV` 所属係マスタのファイル名 master.csv

役職が空欄の人も集計対象外になります。

動作要件

* PHP 7.4 以上 * 拡張:`zip` `xml` `mbstring` * `upload_max_filesize` / `post_max_size` 2MB以上

`check.php` をアップロードして開くと、これらを一括で確認できます。

トラブルシューティング

メッセージ 対処
PHPのZipArchive拡張が有効になっていません サーバーで `zip` 拡張を有効化
必要な列「◯◯」が見つかりません 出勤簿ではなく「月別データ」をダウンロード
対象年月を判定できません ファイル名を変更せずにアップロード
対象年月が7か月以上あります 前月を最終月とする6か月以内で出し直す
ファイルサイズが上限を超えています `php.ini` の `upload_max_filesize` / `post_max_size` を 8M 程度に