本章完成「歷史同盟」四大命令列任務:
gen_dir:多格式(banquet/RTF/HTML)產生會員目錄。need_renewal + renewal_notify:兩階段會員到期通知。edit_member:互動式會員資料編輯(含新增)。interests:關鍵字搜尋共同興趣會員。gen_dir 的轉換盒模式核心邏輯:
my %switchbox = (
banquet => { init => \&banquet_init, entry => \&format_banquet_entry, cleanup => \&banquet_cleanup },
rtf => { init => \&rtf_init, entry => \&format_rtf_entry, cleanup => \&rtf_cleanup },
html => { init => \&html_init, entry => \&format_html_entry, cleanup => \&html_cleanup },
);
執行流程:
%switchbox 取得函式參考 $func_href。$func_href->{init}()。fetchrow_hashref() 逐行呼叫 $func_href->{entry}($row_ref)。$func_href->{cleanup}()。新增格式只需寫三個函式並加入 %switchbox,零修改主流程。
format_banquet_entry():組合姓名、後綴(Jr./Sr. 加逗號,II/III 僅空格)。format_name() 供 RTF/HTML 複用。{\rtf0\fonttbl{\f0 Times;}\plain\f0\fs24 ... }。\b Title\b0),段落結束 \par。<html><body><h1>...,清理輸出 </body></html>。<b>、<br>),並用 escapeHTML() 處理特殊字元。directory.html 置於 Apache htdocs,配合 cron 定時更新(如每天 04:00)。need_renewal 產生名單
SELECT member_id, last_name, first_name, expiration,
DATEDIFF(expiration, CURDATE()) AS days_left
FROM member
WHERE expiration < DATE_ADD(CURDATE(), INTERVAL ? DAY)
ORDER BY days_left;
cutoff 天數由命令列給定(0 表示已過期)。輸出含 days_left(負值=已過期),導向檔案供人工審核。
renewal_notify 發送郵件sendmail 管道(open(MAIL, "|$sendmail"))推入郵件內容。edit_membercol_prompt()),INSERT 新紀錄。member_id → 編輯模式:先查現有值,提示時顯示當前值(col_prompt(..., $show_current=1)),直接 Enter 保留原值,輸入新值則 UPDATE。^\d{4}-\d{2}-\d{2}$),NULL 代表終身會員(空字串會變 0000-00-00 需特殊處理)。interests% 變 LIKE '%keyword%'。format_entry()(去除 RTF 控制碼版)格式化輸出。