RISHIRIS LOGIC EXPLORER
システムロジックの可視化と構成管理
🏠 ホームに戻る
⚙️ 管理モード
🛠️ ロジック・エディタ
アイコン
メインタイトル
削除
🎙️
🔄
📧
📠
⚙️
📼
📂
🖥️
📱
✅
⚠️
🔒
📜
🚀
📡
🛠️
🔗
← 選択して入力
サブタイトル / エンジン名
関連ファイル / パス
実装コード / ロジック説明
ユーザーからのFAX送信を受付する為のメールアドレスが必要 (FAX以外のサービスを必要としない受信の為のメールアドレスです。) ちなみに私は、レンタルサーバーで契約している独自ドメインの メールアドレスを1個、FAX用に作成しそれを受信するようにしてます。 でGmailアプリで、FAXメール宛てに送信してます。
アイコン
メインタイトル
削除
🎙️
🔄
📧
📠
⚙️
📼
📂
🖥️
📱
✅
⚠️
🔒
📜
🚀
📡
🛠️
🔗
← 選択して入力
サブタイトル / エンジン名
関連ファイル / パス
実装コード / ロジック説明
自由にroot権限を扱える物理的なサーバー機が無いと構築もできません。
アイコン
メインタイトル
削除
🎙️
🔄
📧
📠
⚙️
📼
📂
🖥️
📱
✅
⚠️
🔒
📜
🚀
📡
🛠️
🔗
← 選択して入力
サブタイトル / エンジン名
関連ファイル / パス
実装コード / ロジック説明
/home/user名/.fetchmailrc このファイルを使って①で用意したメールアドレスに届いた メールを自動で受信できるように設定します。 設定ファイルの例 poll 受信用サーバー名 # 取得先サーバー(test@test.comとか・・・) protocol IMAP port 993 user "自由に使えるメールアドレス" test@tes.com とか・・・ password "受信用パスワード" # 発行したアプリパスワード メールパスワードを "囲う" is ユーザー名 here # メールの受け取り手 ユーザー名なんでユーザー名だけで良い options ssl options sslcertck # 証明書の検証(よりセキュアに)SSLで接続する場合 options keep # テスト中はサーバーにメールを残す(成功したら 'nokeep' に変更) mda "/usr/bin/procmail -d $USER" こんな感じで①で用意したメールを受信可能な状態にします。 私の場合は・・・1分間隔でメールが来てないか? 自動で確認する設定にしています。 ですのでFAXをメールで送信したら相手に届くまでに 3分くらいして届く場合もあります。 常時待ち受けてるとレンタルサーバー側の処理に負荷が かかるので1分毎に受信するようにしています。 ※メールをLAN内のサーバーで受信していますが、 自宅サーバーでメールサーバーを構築していません。 あくまでも、外にあるメールサーバーに届いたメールを を確認してメールがある場合は、FAXが送信されるように 取り込む形です。 自宅サーバーがドメインを持っていて自宅サーバーに直接 届いたメールを処理しているわけでない (セキュリティー上、こうしてます。) この意味の違いわかるかな?
アイコン
メインタイトル
削除
🎙️
🔄
📧
📠
⚙️
📼
📂
🖥️
📱
✅
⚠️
🔒
📜
🚀
📡
🛠️
🔗
← 選択して入力
サブタイトル / エンジン名
関連ファイル / パス
実装コード / ロジック説明
PATH=/usr/bin:/bin:/usr/local/bin MAILDIR=$HOME/Mail LOGFILE=$HOME/procmail.log VERBOSE=on :0 | /var/www/html/fax/bin/faxmail.sh 自宅のローカルサーバー内にある /var/www/html/fax/bin/faxmail.sh にて 受け取ったメールを解析しFAX番号に送る準備をします。
アイコン
メインタイトル
削除
🎙️
🔄
📧
📠
⚙️
📼
📂
🖥️
📱
✅
⚠️
🔒
📜
🚀
📡
🛠️
🔗
← 選択して入力
サブタイトル / エンジン名
関連ファイル / パス
実装コード / ロジック説明
faxmail.shから来た情報を元にFAX番号に送信します。もし本文に文字がある場合は、送信票の中に値(情報)を埋め込みして 送信先、依頼先、内容、を印字するようにしています。でないと文字だけがA4用紙1枚に印刷され無駄になってしまうので どうせなら送信票にしてしまえと・・・(ナイスアイデア!) 本文と添付ファイルがある場合は、送信票とは別に添付ファイルを付けて、尚且つ送信方票に何枚?添付あるか追記します。 添付ファイルのみは送信票は送らずに添付ファイルのみにしてます。(その場合は、送信票を手動で付ければ良いので)
アイコン
メインタイトル
削除
🎙️
🔄
📧
📠
⚙️
📼
📂
🖥️
📱
✅
⚠️
🔒
📜
🚀
📡
🛠️
🔗
← 選択して入力
サブタイトル / エンジン名
関連ファイル / パス
実装コード / ロジック説明
[general] defaultindication=jp language=ja [from-hikari] ; --- 外線着信入口 (FAX検知を有効化) --- exten => s,1,NoOp(📞 外線着信: ${CALLERID(num)}) same => n,Set(FAXOPT(faxdetect)=yes) same => n,Answer() ; ▼▼▼ 【重要改修】FAX検知用の「間」を作ります ▼▼▼ ; 自動FAXの信号(CNG)は3秒おきに鳴るため、4秒の無音があれば確実に検知できます。 ; これにより、長いガイダンスが流れる前にFAX受信を開始させます。 same => n,Wait(4) ; ▲▲▲ 改修ここまで ▲▲▲ same => n,Background(/usr/local/bin/onsei/zero) same => n,Background(/usr/local/bin/onsei/startup) same => n,Wait(1) same => n,Goto(voice,s,1) ; FAXトーン検知(検知されるとここへジャンプします) exten => fax,1,NoOp(--- FAX Tone Detected ---) same => n,Goto(fax-router,3005,1) [fax-router] ; --- FAX受信・内部仮想FAXプロセス --- exten => 3005,1,NoOp(--- FAX Reception Start (Extension 3005) ---) same => n,Set(RECV_TIME=${STRFTIME(${EPOCH},,%Y年%m月%d日(%A) %H時%M分%S秒)}) same => n,Set(FAX_TIMESTAMP=${STRFTIME(${EPOCH},,%Y%m%d_%H%M%S)}) same => n,Set(FAXFILE=/var/www/html/fax/recv/fax_${FAX_TIMESTAMP}) ; 前回成功した設定(ECM=yes)を維持 same => n,Set(FAXOPT(ecm)=yes) same => n,ReceiveFAX(${FAXFILE}.tif) same => n,Hangup() ; 受信後の通知処理 exten => h,1,NoOp(FAX Receive Status: ${FAXSTATUS}) same => n,ExecIf($["${FAXFILE}" != ""]?System(/var/www/html/fax/bin/fax_notify.sh "${FAXFILE}.tif" "${FAXSTATUS}" "${CALLERID(num)}" "${EXTEN}" "${RECV_TIME}")) [fax-tx-process] ; --- FAX送信専用コンテキスト --- exten => send,1,NoOp(--- FAX Outbound Data Transmission ---) same => n,Set(FAXOPT(ecm)=yes) same => n,SendFAX(${FAX_FILE}) same => n,Set(FAXOPT(headerinfo)=Rishiris-Nas-Fax) same => n,Hangup() ; 送信結果通知 exten => h,1,NoOp(--- Outbound Result Notification ---) same => n,System(/var/www/html/fax/bin/fax_out_notify.sh "${SENDER_MAIL}" "${FAX_DEST}" "${FAXSTATUS}" "${FAXSTATUSSTRING}" "${TOTAL_PAGES}") [voice] ; --- 自動音声応答・認証(変更なし) --- exten => s,1,NoOp(--- Voice Menu ---) same => n,Read(PIN,/usr/local/bin/onsei/pin-number,4,,1,5) same => n,GotoIf($["${PIN}" = "9216"]?record,s,1) same => n,GotoIf($["${PIN}" = "9999"]?voiceplay,s,1) same => n,Goto(ring,s,1) [record] exten => s,1,NoOp(--- Recording Mode ---) same => n,Playback(/usr/local/bin/onsei/zero-prompt) same => n,Record(/usr/local/bin/onsei/zero.wav,2,30,b,#) same => n,Hangup() ;自作留守電再生・削除機能(変更なし) [voiceplay] exten => s,1,NoOp(--- Custom Voicemail Playback System ---) same => n,Set(VM_DIR=/var/spool/asterisk/voicemail/default/3000/INBOX) same => n,Set(IDX=1) same => n(check_count),Set(MSG_COUNT=${SHELL(ls -1 ${VM_DIR}/*.wav 2>/dev/null | wc -l | tr -d '\n')}) same => n,GotoIf($[${MSG_COUNT} = 0]?empty) same => n(get_file),Set(TARGET_FULL=${SHELL(ls -1t ${VM_DIR}/*.wav | sed -n ${IDX}p | tr -d '\n')}) same => n,GotoIf($["${TARGET_FULL}" = ""]?no_more) same => n,Set(TARGET_FILE=${SHELL(echo "${TARGET_FULL}" | sed 's/\.wav//' | tr -d '\n')}) same => n,Playback(/usr/local/bin/onsei/vm-message) same => n,SayNumber(${IDX}) same => n(menu),Read(ACTION,/usr/local/bin/onsei/play_menu,1,,1,5) same => n,GotoIf($["${ACTION}" = "1"]?play_msg) same => n,GotoIf($["${ACTION}" = "#"]?next_msg) same => n,GotoIf($["${ACTION}" = "9"]?del_msg) same => n,GotoIf($["${ACTION}" = "*"]?exit) same => n,Goto(menu) same => n(play_msg),Playback(${TARGET_FILE}) same => n,Goto(menu) same => n(next_msg),Set(IDX=$[${IDX} + 1]) same => n,Goto(get_file) same => n(del_msg),System(rm ${TARGET_FILE}.wav ${TARGET_FILE}.txt) same => n,Playback(/usr/local/bin/onsei/vm-deleted) same => n,Goto(check_count) same => n(no_more),Playback(/usr/local/bin/onsei/vm-no-more) same => n,Set(IDX=1) same => n,Goto(check_count) same => n(empty),Playback(/usr/local/bin/onsei/vm-no-messages) same => n,Wait(1) same => n,Hangup() same => n(exit),Hangup() [ring] exten => s,1,NoOp(--- Calling 3000 then Voicemail ---) same => n,Set(VM_DIR=/var/spool/asterisk/voicemail/default/3000/INBOX) same => n,Set(START_TIME=${EPOCH}) same => n,Set(current_name=manual-vm-${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${CALLERID(num)}) same => n,Ringing() same => n,Dial(PJSIP/3000,11,r) same => n,Set(ELAPSED=$[${EPOCH} - ${START_TIME}]) same => n,ExecIf($[${ELAPSED} < 11]?Wait($[11 - ${ELAPSED}])) same => n,NoOp(--- 11 seconds limit reached: Playing Guidance ---) same => n,Playback(/usr/local/bin/onsei/end) same => n,System(echo 'callerid="${CALLERID(name)}" <${CALLERID(num)}>' > ${VM_DIR}/${current_name}.txt) same => n,System(echo 'origtime=${EPOCH}' >> ${VM_DIR}/${current_name}.txt) same => n,Record(${VM_DIR}/${current_name}.wav,5,60,k) same => n,System(echo 'duration=${RECORDED_DURATION}' >> ${VM_DIR}/${current_name}.txt) same => n,Hangup() ; --- 終了時処理(変更なし) --- exten => h,1,NoOp(--- Hangup Handling ---) ; --- 終了時処理 --- exten => h,1,NoOp(--- Hangup Handling ---) ; 変数 current_name が空でないかチェックしてスクリプト実行 ; 録音ファイルパスには .wav を付けずに渡す(スクリプト側で補完されます) exten => h,n,ExecIf($[ "${current_name}" != "" ]?System(/var/www/html/fax/bin/voicemail-mp3-send.sh "${CALLERID(num)}" "${VM_DIR}/${current_name}" "留守録を添付で送りたいメールアドレス"))
アイコン
メインタイトル
削除
🎙️
🔄
📧
📠
⚙️
📼
📂
🖥️
📱
✅
⚠️
🔒
📜
🚀
📡
🛠️
🔗
← 選択して入力
サブタイトル / エンジン名
関連ファイル / パス
実装コード / ロジック説明
一応は、この流れでFAXが相手に届きます。
アイコン
メインタイトル
削除
🎙️
🔄
📧
📠
⚙️
📼
📂
🖥️
📱
✅
⚠️
🔒
📜
🚀
📡
🛠️
🔗
← 選択して入力
サブタイトル / エンジン名
関連ファイル / パス
実装コード / ロジック説明
録音された音声ファイルはmp3に変換され保存されます。 私の場合は、mp3に変換したファイルを次の工程スクリプトで 指定メールアドレスに添付します。 ちなみにですが、こんな事しなくても AsteriskにはVoicemail.confに指定メールアドレスを かけば、添付してくれますが、私は色々とやってみたい方なので(笑) 別途スクリプトによって添付してもらってます。
アイコン
メインタイトル
削除
🎙️
🔄
📧
📠
⚙️
📼
📂
🖥️
📱
✅
⚠️
🔒
📜
🚀
📡
🛠️
🔗
← 選択して入力
サブタイトル / エンジン名
関連ファイル / パス
実装コード / ロジック説明
以下のコードを動かして指定のメールアドレスは、extensions.conf の最後に指定 しています。 #!/bin/bash # ========================================================== # Asterisk Voicemail to MP3 Emailer (V2: Cool Format) # Path: /var/www/html/fax/bin/voicemail-mp3-send.sh # ========================================================== # 1. 引数の受け取り CALLER_ID="$1" FILE_PATH="$2" EMAIL_TO="$3" MUTT_CONFIG="/etc/mutt_postfix.rc" LOGFILE="/var/log/asterisk/vm_script.log" # 2. ファイルパスの判定 if [ -f "$FILE_PATH" ]; then WAV_FILE="$FILE_PATH" elif [ -f "${FILE_PATH}.wav" ]; then WAV_FILE="${FILE_PATH}.wav" else echo "$(date) [ERROR] WAV File not found: $FILE_PATH" >> "$LOGFILE" exit 1 fi # 作業用変数の作成 BASENAME=$(basename "$WAV_FILE") DIRNAME=$(dirname "$WAV_FILE") MP3_FILE="${DIRNAME}/${BASENAME%.*}.mp3" # 3. WAV -> MP3 変換 # ffmpegを自動で探して実行 FFMPEG_CMD=$(which ffmpeg 2>/dev/null) if [ -z "$FFMPEG_CMD" ]; then FFMPEG_CMD="/usr/local/bin/ffmpeg"; fi "$FFMPEG_CMD" -y -i "$WAV_FILE" -acodec libmp3lame -b:a 192k "$MP3_FILE" >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "$(date) [ERROR] ffmpeg conversion failed." >> "$LOGFILE" MP3_FILE="$WAV_FILE" fi # 4. 音声ファイルの秒数を取得 SOXI_CMD=$(which soxi 2>/dev/null) if [ -z "$SOXI_CMD" ]; then SOXI_CMD="/usr/local/bin/soxi"; fi if [ -x "$SOXI_CMD" ]; then # 秒数を取得し、小数点以下を切り捨てて0埋め2桁にする (例: 3 -> 03) SEC_RAW=$("$SOXI_CMD" -D "$WAV_FILE" 2>/dev/null | cut -d. -f1) if [ -z "$SEC_RAW" ]; then SEC_RAW=0; fi DURATION_SEC=$(printf "%02d" $SEC_RAW) else DURATION_SEC="00" fi # 5. 日付と時刻のフォーマット (ご要望に合わせて変更) # 例: 2026年01月31日 DATE_STR=$(date "+%Y年%m月%d日") # 例: 14時07分00秒 TIME_STR=$(date "+%H時%M分%S秒") # 6. メール本文の作成 (ご要望のデザイン) BODY_TEXT="日時:${DATE_STR} 時間:${TIME_STR} ファイル名:$(basename "$MP3_FILE") 秒数:${DURATION_SEC}秒" # 7. メール送信 # 件名を変更: [留守電] -> 留守電: MUTT_CMD=$(which mutt 2>/dev/null) if [ -z "$MUTT_CMD" ]; then MUTT_CMD="/usr/bin/mutt"; fi echo "$BODY_TEXT" | "$MUTT_CMD" -F "$MUTT_CONFIG" \ -s "留守電:${CALLER_ID}" \ -a "$MP3_FILE" \ -- "$EMAIL_TO" # 8. 完了ログ echo "$(date) [INFO] Sent VM from $CALLER_ID to $EMAIL_TO" >> "$LOGFILE" exit 0
アイコン
メインタイトル
削除
🎙️
🔄
📧
📠
⚙️
📼
📂
🖥️
📱
✅
⚠️
🔒
📜
🚀
📡
🛠️
🔗
← 選択して入力
サブタイトル / エンジン名
関連ファイル / パス
実装コード / ロジック説明
自宅からフォームで送信可能です。以下は自宅用の送信フォームです。 送信したファイルも受信したファイルも確認削除可能です。 これはAsteriskへファイルを送信してます。 <?php /** * Rishiris-Nas-Fax Portal - Ultimate Management Version * 修正点: * 1. 送信者リスト(senders.json)から連動してメールを自動入力する機能を追加 * 2. htmlspecialchars() の PHP 8.1+ 対応(nullチェック) * 3. 送信履歴の削除を「赤いボタン」のデザインで確実に表示 * 4. ファイルがなくても履歴(JSON)から消去できるようにロジックを分離 */ // エラー表示設定 ini_set('display_errors', 1); error_reporting(E_ALL); // --- 設定エリア --- $base_dir = "/var/www/html/fax"; $status_dir = "$base_dir/status"; $sent_dir = "$base_dir/sent"; $recv_dir = "$base_dir/recv"; $spool_dir = "/var/spool/asterisk/outgoing"; $log_file = "/tmp/web_fax_log.txt"; $contactsFile = "$status_dir/contacts.json"; $sendersFile = "$status_dir/senders.json"; // 送信者データ $jobs_file = "$status_dir/jobs.json"; // 必要なディレクトリの作成 foreach ([$status_dir, $sent_dir, $recv_dir] as $d) { if (!file_exists($d)) @mkdir($d, 0777, true); } // ログ記録関数 function write_log($msg) { global $log_file; @file_put_contents($log_file, "[" . date("Y-m-d H:i:s") . "] $msg\n", FILE_APPEND); } // --- 1. 削除処理 (ページ上部で真っ先に実行) --- if (isset($_GET['del_file']) && isset($_GET['type'])) { $type = $_GET['type']; $filename = basename($_GET['del_file']); $target_path = ($type === 'sent' ? $sent_dir : $recv_dir) . "/" . $filename; // A. 物理ファイルの削除 if ($filename !== "" && file_exists($target_path)) { @unlink($target_path); } // B. 履歴リスト(JSON)からの削除(送信履歴の場合) if ($type === 'sent') { $temp_jobs = file_exists($jobs_file) ? json_decode(file_get_contents($jobs_file), true) : []; $updated = false; foreach ($temp_jobs as $id => $j) { if ((isset($j['file']) && $j['file'] === $filename) || $filename === "") { unset($temp_jobs[$id]); $updated = true; } } if ($updated) { file_put_contents($jobs_file, json_encode($temp_jobs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); } } // 削除後はリダイレクトして表示を更新 header("Location: index.php#tab-" . ($type === 'sent' ? 'history' : 'recv')); exit; } // データの読み込み $contacts = file_exists($contactsFile) ? json_decode(file_get_contents($contactsFile), true) : []; $senders = file_exists($sendersFile) ? json_decode(file_get_contents($sendersFile), true) : []; $jobs = file_exists($jobs_file) ? json_decode(file_get_contents($jobs_file), true) : []; $message = ""; $status_class = "info"; // --- 2. FAX送信処理 --- if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['send_fax'])) { $ts = date("Ymd_His"); $work_id = "W" . $ts; $work_dir = "/tmp/fax_{$work_id}"; @mkdir($work_dir, 0777, true); $target_num = ($_POST['fax_dest'] === 'manual') ? $_POST['manual_num'] : $_POST['fax_dest']; $faxnum = preg_replace('/[^0-9]/', '', $target_num); $sender_name = $_POST['sender_name'] ?: "Web User"; $sender_email = $_POST['sender_email'] ?: "結果を送信したいメールアドレス"; $body_content = $_POST['body_text'] ?: "(本文なし)"; $attachments = []; if (!empty($_FILES['fax_files']['name'][0])) { foreach ($_FILES['fax_files']['tmp_name'] as $i => $tmp_path) { if ($_FILES['fax_files']['error'][$i] === UPLOAD_ERR_OK) { $ext = pathinfo($_FILES['fax_files']['name'][$i], PATHINFO_EXTENSION); $save_path = "$work_dir/attach_{$i}.{$ext}"; move_uploaded_file($tmp_path, $save_path); $attachments[] = $save_path; } } } $tif_filename = "send_{$ts}.tif"; $tif_out = "$sent_dir/$tif_filename"; // デザイナーズ送信票作成 $border = "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"; $cover_text = "┏{$border}┓\n┃ ┃\n┃ R i s h i r i s - N a s - F a x 送 信 票 ┃\n┃ ┃\n┗{$border}┛\n\n 送信日時: " . date("Y年m月d日 H時i分s秒") . "\n 宛先番号: {$faxnum}\n 総送信数: 全 ".(1+count($attachments))." 枚\n\n 【 送 信 元 】 {$sender_name} <{$sender_email}>\n\n ■ メッセージ内容\n " . str_repeat("-", 60) . "\n\n" . preg_replace('/^/m', ' ', $body_content) . "\n\n " . $border; file_put_contents("$work_dir/cover.txt", $cover_text); exec("paps --font=\"IPAGothic 12\" " . escapeshellarg("$work_dir/cover.txt") . " > " . escapeshellarg("$work_dir/cover.ps")); // TIFF変換 $gs_inputs = array_merge(["$work_dir/cover.ps"], $attachments); $gs_input_str = implode(" ", array_map('escapeshellarg', $gs_inputs)); exec("/usr/bin/gs -q -dNOPAUSE -dBATCH -sDEVICE=tiffg4 -sPAPERSIZE=a4 -r204x196 -sOutputFile=" . escapeshellarg($tif_out) . " " . $gs_input_str . " 2>&1", $gs_output, $gs_res); if ($gs_res === 0 && file_exists($tif_out)) { chmod($tif_out, 0666); $call_file = "/tmp/web_fax_{$ts}.call"; $target_chan = ($faxnum === "3005") ? "Local/3005@fax-router/n" : "PJSIP/{$faxnum}@hikari-trunk"; $call_data = "Channel: {$target_chan}\nContext: fax-tx-process\nExtension: send\nPriority: 1\nMaxRetries: 2\nRetryTime: 60\nWaitTime: 45\n"; $call_data .= "Set: FAX_FILE={$tif_out}\nSet: SENDER_MAIL={$sender_email}\nSet: FAX_DEST={$faxnum}\nSet: TOTAL_PAGES=".(1+count($attachments))."\n"; file_put_contents($call_file, $call_data); if (copy($call_file, "$spool_dir/" . basename($call_file))) { unlink($call_file); $jobs[$work_id] = ["time" => date("Y-m-d H:i:s"), "dest" => $faxnum, "file" => $tif_filename, "status" => "Queued"]; file_put_contents($jobs_file, json_encode(array_slice($jobs, -30, null, true), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); $message = "✅ FAX送信を開始しました。ID: $work_id"; $status_class = "success"; write_log("Web-FAX 投入成功: To $faxnum"); } } } // 表示用データの準備 $recv_files = array_reverse(glob("$recv_dir/*.{tif,pdf}", GLOB_BRACE)); $log_content = file_exists($log_file) ? shell_exec("tail -n 20 " . escapeshellarg($log_file)) : "ログはありません。"; ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Rishiris-Nas-Fax Portal</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <style> body { background: #f4f7f6; font-family: sans-serif; font-size: 0.9rem; } .container { max-width: 1000px; } .card { border: none; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.08); } .nav-tabs .nav-link { border: none; font-weight: 600; color: #888; padding: 12px 20px; } .nav-tabs .nav-link.active { color: #0d6efd; background: white; border-bottom: 3px solid #0d6efd; } .btn-action { font-weight: bold; border-radius: 6px; padding: 2px 10px; font-size: 0.8rem; } </style> </head> <body> <nav class="navbar navbar-dark bg-dark mb-4"> <div class="container"><span class="navbar-brand">📠 Rishiris-Nas-Fax Gateway</span></div> </nav> <div class="container"> <?php if($message): ?> <div class="alert alert-<?= $status_class ?> alert-dismissible fade show"><?= $message ?><button type="button" class="btn-close" data-bs-dismiss="alert"></button></div> <?php endif; ?> <ul class="nav nav-tabs mb-0" id="mainTab"> <li class="nav-item"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#tab-send">FAX送信</button></li> <li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-recv">受信一覧</button></li> <li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-history">送信履歴</button></li> <li class="nav-item"><a class="nav-link" href="contacts.php">アドレス帳</a></li> <li class="nav-item"><a class="nav-link" href="senders.php">送信者管理</a></li> </ul> <div class="tab-content bg-white p-4 card" style="border-top-left-radius: 0;"> <div class="tab-pane fade show active" id="tab-send"> <form action="" method="post" enctype="multipart/form-data"> <div class="row g-3"> <div class="col-md-6"> <label class="form-label fw-bold">送信先を選択</label> <select name="fax_dest" class="form-select" onchange="toggleManual(this)"> <option value="manual">直接入力...</option> <?php foreach($contacts as $num => $name): ?> <option value="<?= htmlspecialchars((string)$num) ?>"><?= htmlspecialchars((string)$name) ?> (<?= htmlspecialchars((string)$num) ?>)</option> <?php endforeach; ?> </select> </div> <div class="col-md-6" id="manual_box"> <label class="form-label fw-bold">番号入力 (直接入力時)</label> <input type="text" name="manual_num" class="form-control" placeholder="0163857171"> </div> <div class="col-md-6"> <label class="form-label fw-bold">送信者を選択 (連動)</label> <select id="sender_select" class="form-select" onchange="updateSender(this)"> <option value="" data-email="">選択してください...</option> <?php foreach($senders as $s): ?> <option value="<?= htmlspecialchars((string)$s['name']) ?>" data-email="<?= htmlspecialchars((string)$s['email']) ?>"> <?= htmlspecialchars((string)$s['name']) ?> </option> <?php endforeach; ?> <option value="manual" data-email="">手入力...</option> </select> </div> <div class="col-md-6"> <label class="form-label fw-bold">送信者氏名</label> <input type="text" name="sender_name" id="sender_name" class="form-control" required> </div> <div class="col-12"> <label class="form-label fw-bold">通知先メールアドレス</label> <input type="email" name="sender_email" id="sender_email" class="form-control" required> </div> <div class="col-12"><label class="form-label fw-bold">本文メッセージ</label><textarea name="body_text" class="form-control" rows="3"></textarea></div> <div class="col-12"><label class="form-label fw-bold">PDF添付</label><input type="file" name="fax_files[]" class="form-control" multiple accept=".pdf"></div> <div class="col-12 text-center mt-3"><button type="submit" name="send_fax" class="btn btn-primary btn-lg px-5">FAX送信を開始</button></div> </div> </form> </div> <div class="tab-pane fade" id="tab-recv"> <table class="table table-hover align-middle"> <thead><tr><th>日時</th><th>ファイル</th><th class="text-center">操作</th></tr></thead> <tbody> <?php if(empty($recv_files)): ?><tr><td colspan="3" class="text-center text-muted py-4">受信なし</td></tr><?php endif; ?> <?php foreach($recv_files as $f): $fn = basename($f); ?> <tr> <td><?= date("Y-m-d H:i", filemtime($f)) ?></td> <td><code><?= htmlspecialchars($fn) ?></code></td> <td class="text-center"> <a href="recv/<?= htmlspecialchars($fn) ?>" class="btn btn-outline-success btn-action me-1" target="_blank">表示</a> <a href="?type=recv&del_file=<?= urlencode($fn) ?>#tab-recv" class="btn btn-danger btn-action text-white" onclick="return confirm('受信ファイルを完全に削除しますか?')">削除</a> </td> </tr> <?php endforeach; ?> </tbody> </table> </div> <div class="tab-pane fade" id="tab-history"> <table class="table table-hover align-middle"> <thead><tr><th>送信日時</th><th>宛先</th><th>状態</th><th class="text-center">操作</th></tr></thead> <tbody> <?php if(empty($jobs)): ?><tr><td colspan="4" class="text-center text-muted py-4">送信履歴はありません</td></tr><?php endif; ?> <?php foreach(array_reverse($jobs, true) as $id => $j): $fn = $j['file'] ?? ""; ?> <tr> <td><?= htmlspecialchars((string)$j['time']) ?></td> <td><?= htmlspecialchars((string)$j['dest']) ?></td> <td><span class="badge bg-secondary"><?= htmlspecialchars((string)$j['status']) ?></span></td> <td class="text-center"> <?php if($fn): ?> <a href="sent/<?= htmlspecialchars((string)$fn) ?>" target="_blank" class="btn btn-outline-primary btn-action me-1">表示</a> <?php endif; ?> <a href="?type=sent&del_file=<?= urlencode((string)$fn) ?>#tab-history" class="btn btn-danger btn-action text-white" onclick="return confirm('履歴とファイルを削除しますか?')">削除</a> </td> </tr> <?php endforeach; ?> </tbody> </table> </div> <div class="tab-pane fade" id="tab-logs"> <div class="bg-dark text-white p-3 rounded" style="min-height: 200px; font-family: monospace;"> <pre class="mb-0 text-white"><code><?= htmlspecialchars($log_content) ?></code></pre> </div> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script> function toggleManual(sel) { document.getElementById('manual_box').style.display = (sel.value === 'manual') ? 'block' : 'none'; } // 送信者選択時に名前とメールを連動させるJS function updateSender(sel) { const opt = sel.options[sel.selectedIndex]; const nameInput = document.getElementById('sender_name'); const emailInput = document.getElementById('sender_email'); if (sel.value === 'manual') { nameInput.value = ''; emailInput.value = ''; nameInput.focus(); } else if (sel.value !== '') { nameInput.value = sel.value; emailInput.value = opt.getAttribute('data-email'); } } document.addEventListener('DOMContentLoaded', function() { var hash = window.location.hash; if (hash) { var triggerEl = document.querySelector('button[data-bs-target="' + hash + '"]'); if (triggerEl) { (new bootstrap.Tab(triggerEl)).show(); } } }); </script> </body>
アイコン
メインタイトル
削除
🎙️
🔄
📧
📠
⚙️
📼
📂
🖥️
📱
✅
⚠️
🔒
📜
🚀
📡
🛠️
🔗
← 選択して入力
サブタイトル / エンジン名
関連ファイル / パス
実装コード / ロジック説明
こうする事で外部に公開している訳では ないのでAsterisk的にも安心してFAX送信が可能となります。 mailを送れる環境さえあれば、FAXができる(そう意味で安全)
アイコン
メインタイトル
削除
🎙️
🔄
📧
📠
⚙️
📼
📂
🖥️
📱
✅
⚠️
🔒
📜
🚀
📡
🛠️
🔗
← 選択して入力
サブタイトル / エンジン名
関連ファイル / パス
実装コード / ロジック説明
フォームメールを作成してやれば、外からでもスマホやPCにて FAX画面を見ながら送信が可能となります。 だってファクスメールにメールを送るページを作ってしまえば それでFAX送信できるので!大変便利です。 (スクリプトはセキュリティー上、公開はしませんので) ただし・・・今更FAX?ってなりますよね? 私は、仕事で各お客様宅に行っては、FAXの送受信を確認 しなければいけない時があります。私にとっては、 とても重宝してる仕組みです。 でないと誰かにfax送って!!ってなるし、その人が居なければ 時間の無駄ですもん!(相手を待っていないといけない)
+ 新しいステップを最後に追加
💾 すべての変更を保存して反映
📧
mailアドレス
①自由に使えるメールアドレス
→
🖥️
サーバー (Mail to Fax)
②自由に使えるサーバー機
→
🔄
.fetchmailrc
③メール自動受信用
→
🔄
.procmailrc
④シェルスクリプト実行
→
⚙️
Asterisk
Asteriskが待ち受ける
→
⚙️
extensions.comnf
Asteriskコンフィグ
→
📠
FAX送信
どこにいてもFAXが送信され相手に届く
→
🎙️
おまけ
自宅に電話がかかってきた場合
→
📧
留守電がメールで!
どにいても留守電が飛んでくる!
→
🖥️
さらに・・・
ローカルサーバーでは・・・
→
📱
Mail To Fax・・・
利点
→
📱
さらに!
外部WEBサーバーを工夫して
Viewer
Source: Not Selected
// アイコンをクリックすると詳細が表示されます。