平文でメール発信していたツールを、6月に向けて、SSL型に移行するため、
PHPに書き換えたいが、腰が重くなっていた。
話題のClaude3に任せることにしたら、ほぼそのまま、SSL型メール発信になった。
参考にしたいという人もいるので、Before/Afterで、ソースコードを載せる。
元のPerl-CGI
#!/usr/local/bin/perl
# モジュール宣言
use strict;
use utf8;
use CGI::Carp qw(fatalsToBrowser);
use lib "./lib";
# use CGI::Minimal;
use CGI;
use URI::Escape;
use File::Copy;
use File::Basename;
use Encode qw(decode);
use JSON;
# データ受理
# CGI::Minimal::max_read_size(10240);
my $cgi = CGI->new;
my %in = &parse_form($cgi);
my %hash ;
my $date = $in{date};
my $str_crypt = $in{str_crypt};
my $str_plain;
# 初期モード
my $ret = 0;
my $personc = Encode::decode('utf8',$in{addrJ});
my $join;
my $body;
my $mbody;
&header();
print $in{addrJ};
my $addrJ = decode_json($in{addrJ}); print "$@";
my $title = Encode::decode('utf8',$in{subject});
print $title."<br>";
# for my $person (@$addrJ) {for my $clm (@$person) {print "$clm<br>\n";}};
my $upfile = "";
my $upfile2 = "";
if ($in{attach} ne "") {
$upfile = basename($in{attach});
my $fh = $cgi->param('attach');
copy ($fh, "../temp/$upfile");
}
if ($in{attach2} ne "") {
$upfile2 = basename($in{attach2});
my $fh = $cgi->param('attach2');
copy ($fh, "../temp/$upfile2");
}
# 認証
if ($in{mode} eq "chkMl") {
require './lib/captcha.pl';
($str_plain, $str_crypt) = cap::make( 'captclipbrd', 6 );
}
foreach my $addr (@$addrJ) {
my @pers = @$addr;
if ($#pers > 1) {
my $email = @$addr[2];
my $eemail = $email;
$eemail =~ s/\@/@/;
my $name = @$addr[1];
my $nenji = @$addr[0];
$join = $nenji."卒) ".$name." 様";
$mbody = Encode::decode('utf8',$in{mbody});
$mbody =~ s/!EMAIL!/$eemail/g;
if ($in{mode} eq "sendMl") { &checKey(); }
# 改行処理<br>
$body = $join."\n".$mbody;
# 依頼者へのメールテキスト出力
if (($in{mode} eq "sendMl")||($in{mode} eq "mailIn")) {
$ret = &sendMail($title,$name,$email,$in{email},$body);
print "メール発信を実施しました。".$in{email}." ".$ret."<br>\n";
}
elsif ($in{mode} eq "chkMl") {
# 画面展開
if ($body eq "【ファイル】") {
$body = $join;
}
# 改行処理
$body .= "\nこのメッセージの発信には、次の投稿キーが必要です。\n";
$body .= $str_plain."\n";
$ret = &sendMail($title."(プレビュー)",$name,$in{email},$in{email},$body);
$body =~ s/\r\n/<br>/g;
$body =~ s/\r/<br>/g;
$body =~ s/\n/<br>/g;
print $body;
&error("発信のプレビューがあなたにメール送信されました。".$ret);
}
}
}
print "</body></html>";
exit();
#-----------------------------------------------------------
# HTMLヘッダー
#-----------------------------------------------------------
sub header {
my $ttl = shift;
print "Content-type: text/html\n\n";
print <<EOM;
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="content-style-type" content="text/css">
<style type="text/css">
<!--
body,td,th { font-size: 13px; }
.ttl { color: #004040; }
-->
</style>
<title>$ttl</title>
</head>
<body>
EOM
}
#-----------------------------------------------------------
# フォームデコード
#-----------------------------------------------------------
sub parse_form {
my $cgi = shift;
my %in;
# if ($ENV{'QUERY_STRING'} ne "") { &error ("フォームの外からの要求です");}
$in{xls} = "";
foreach ( $cgi->param() ) {
my $val = $cgi->param($_);
if (($_ ne 'addrJ') && ($_ ne 'mbody') && ($_ ne 'upfile')) {
# 無効化
$val =~ s/&/&/g;
$val =~ s/</</g;
$val =~ s/>/>/g;
$val =~ s/"/"/g;
$val =~ s/'/'/g;
# 改行処理
$val =~ s/\r\n/<br>/g;
$val =~ s/\r/<br>/g;
$val =~ s/\n/<br>/g;
}
$in{$_} = $val;
}
return %in;
}
#-----------------------------------------------------------
# エラー画面
#-----------------------------------------------------------
sub error {
my $err = shift;
my $ext = shift;
my $tmpl = <<HTML;
<hr width="350">
<p>!message!</p>
<form name=form1 action="//mori1-hakua.tokyo/cgi-bin/test/sendMK.cgi" ENCTYPE="multipart/form-data" method="post">
<input type="hidden" name="mode" value="chkMl">
<input type="hidden" name="addrJ" value='$personc'>
<input type="hidden" name="sama" value="$join">
<input type="hidden" name="len" value="0">
<input type="hidden" name="subject" value="$title">
<input type="hidden" name="mbody" value='$mbody'>
<input type="hidden" name="email" value="$in{email}">
<input type="hidden" name="str_crypt" value="$str_crypt">
<table cellpadding="1" cellspacing="1" id="reqMail">
<tr>
<!-- captcha_begin -->
<td class="item">投稿キー</td>
<td class="small"><input type="number" name="captcha" size="6" style="ime-mode: disabled;" maxlength="6" value="">
(プレビューで通知された数字を入力)
</td>
<!-- captcha_end -->
</tr><tr>
<td class="item" valign="top">添付ファイル</td>
<td> <input type="file" name="attach"></td>
</tr><tr>
<td class="item" valign="top">添付ファイル2</td>
<td> <input type="file" name="attach2"></td>
</tr><tr>
<td></td><td align="right">
<input type="submit" id="send" value="送信" !disable! onclick='form1.mode.value="sendMl";'>
<input type="button" value="戻る" onclick="window.close()">
</td>
</tr>
</table></form></body></html>
HTML
if ($ext==3) {
$tmpl =~ s/!message!/$err/;
$tmpl =~ s/!disable!/disabled/;
} else {
$tmpl =~ s/!message!/<font color=red>$err<\/font>/;
$tmpl =~ s/!disable!//;
}
print $tmpl;
exit;
}
#-----------------------------------------------------------
# 添付メール送信
#-----------------------------------------------------------
sub sendMail
{
my ($title,$name,$email,$org,$body) = @_;
# $email =~ s/@/\\@/g;
require '/home/users/1/main.jp-mori1-mp/web/clipbbs/tmpl/sendMail.pl';
# 添付ファイル付きでメールを送る
# 引数 (添付ファイルパス・拡張子, 添付するパス無しファイル名の年次部分配列,
# 差出人名, 差出人メールアドレス, 送信先名, 送信先メールアドレス,
# 件名, 本文 [, 返信先名, 返信先メールアドレス, 日時とホストを無追記]
# [, Cc名, Ccアドレス, Bcc名, Bccアドレス])
return &sendmail_attach (["/home/users/1/main.jp-mori1-mp/web/wp31/cgi-bin/temp/",""],
["$upfile","$upfile2"],
"在京白堊会事務局",$org,$name,$email,
$title,
$body,
"年次幹事",$org,0,"","","在京白堊会事務局","");
}
#-----------------------------------------------------------
# 投稿文字認証
#-----------------------------------------------------------
sub checKey {
# 要求キーチェック
require './lib/captcha.pl';
if ($in{captcha} !~ /^\d{6}$/) {
&error("投稿キーが入力不備です。<br>プレビューで通知を受けたキーを入力してください");
}
# 要求キーチェック
# -1 : キー不一致
# 0 : 制限時間オーバー
# 1 : キー一致
my $chk = cap::check($in{captcha}, $in{str_crypt},'captclipbrd',10, 6);
if ($chk == 0) {
&error("投稿キーが有効時間を超過しました。<br>プレビューをやり直してください");
} elsif ($chk == -1) {
&error("投稿キーが不正です。<br>プレビューで通知を受けたキーを入力してください");
}
}
変換後のPHPmailerによるプログラム
<?php
// モジュール宣言
error_reporting(E_ALL & ~E_NOTICE);
ini_set("display_errors", "1"); //エラー表示:1 非表示:0
ini_set('magic_quotes_runtime', false);
date_default_timezone_set('Asia/Tokyo');
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require_once '../../PHPMailer/src/Exception.php';
require_once '../../PHPMailer/src/PHPMailer.php';
require_once '../../PHPMailer/src/SMTP.php';
mb_language("japanese");
mb_internal_encoding("UTF-8");
// データ受理
$in = $_POST;
// 初期値の設定
$str_plain = "";
$str_crypt = "";
$ret = 0;
$personc = mb_convert_encoding($in['addrJ'], "UTF-8", "auto");
$join = "";
$body = "";
$mbody = "";
$addrJ = json_decode($in['addrJ']);
$title = mb_convert_encoding($in['subject'], "UTF-8", "auto");
header_html();
echo $personc."<br>";
echo $title."<br>";
$upfile = "";
$upfile2 = "";
// 添付ファイルの処理
if (!empty($_FILES['attach']['tmp_name'])) {
$upfile = basename($_FILES['attach']['name']);
$tmp_path = $_FILES['attach']['tmp_name'];
move_uploaded_file($tmp_path, "../temp/$upfile");
}
if (!empty($_FILES['attach2']['tmp_name'])) {
$upfile2 = basename($_FILES['attach2']['name']);
$tmp_path = $_FILES['attach2']['tmp_name'];
move_uploaded_file($tmp_path, "../temp/$upfile2");
}
// 認証
// 投稿キーの生成
if ($in['mode'] === "chkMl") {
$str_plain = generateKey(6);
$str_crypt = serialize(array('time' => time(), 'key' => $str_plain));
}
// メール本文の作成とメール送信
foreach ($addrJ as $addr) {
if (count($addr) > 2) {
$email = $addr[2];
$eemail = str_replace('@', '\\@', $email);
$name = $addr[1];
$nenji = $addr[0];
$join = $nenji . "卒) " . $name . " 様";
$mbody = mb_convert_encoding($in['mbody'], "UTF-8", "auto");
$mbody = str_replace("!EMAIL!", $eemail, $mbody);
if ($in['mode'] === "sendMl") {
if (!checkKey($in['captcha'], $in['str_crypt'])) {
echo "<p style='color:red;'>投稿キーが不正です。プレビューで通知を受けたキーを入力してください。</p>";
continue;
}
}
$body = $join . "\n" . $mbody;
if ($in['mode'] === "sendMl" || $in['mode'] === "mailIn") {
$ret = sendMail($title, $name, $email, $in['email'], $body);
echo "メール発信を実施しました。" . $email . " " . $ret . "<br>\n";
} elseif ($in['mode'] === "chkMl") {
if ($body === "【ファイル】") {
$body = $join;
}
echo nl2br($body);
$body .= "\nこのメッセージの発信には、次の投稿キーが必要です。\n";
$body .= $str_plain . "\n";
$ret = sendMail($title . "(プレビュー)", $name, $in['email'], $in['email'], $body);
$body = nl2br($body);
error("発信のプレビューがあなたにメール送信されました。" . $ret);
}
}
}
echo "</body></html>";
exit();
function header_html($ttl = '') {
echo "Content-type: text/html\n\n";
echo <<<EOM
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="content-style-type" content="text/css">
<style type="text/css">
<!--
body,td,th { font-size: 13px; }
.ttl { color: #004040; }
-->
</style>
<title>$ttl</title>
</head>
<body>
EOM;
}
function error($err, $ext = 0) {
global $personc, $join, $title, $mbody, $in, $str_crypt;
$tmpl = <<<HTML
<hr width="350">
<p>!message!</p>
<form name="form1" action="//mori1-hakua.tokyo/cgi-bin/test/sendMK.php" ENCTYPE="multipart/form-data" method="post">
<input type="hidden" name="mode" value="chkMl">
<input type="hidden" name="addrJ" value='$in[addrJ]'>
<input type="hidden" name="sama" value="$join">
<input type="hidden" name="len" value="0">
<input type="hidden" name="subject" value="$title">
<input type="hidden" name="mbody" value='$mbody'>
<input type="hidden" name="email" value="$in[email]">
<input type="hidden" name="str_crypt" value='$str_crypt'>
<table cellpadding="1" cellspacing="1" id="reqMail">
<tr>
<td class="item">投稿キー</td>
<td class="small"><input type="number" name="captcha" size="6" style="ime-mode: disabled;" maxlength="6" value="">
(プレビューで通知された数字を入力)
</td>
</tr><tr>
<td class="item" valign="top">添付ファイル</td>
<td> <input type="file" name="attach"></td>
</tr><tr>
<td class="item" valign="top">添付ファイル2</td>
<td> <input type="file" name="attach2"></td>
</tr><tr>
<td></td><td align="right">
<input type="submit" id="send" value="送信" !disable! onclick='form1.mode.value="sendMl";'>
<input type="button" value="戻る" onclick="window.close()">
</td>
</tr>
</table></form></body></html>
HTML;
if ($ext == 3) {
$tmpl = str_replace('!message!', $err, $tmpl);
$tmpl = str_replace('!disable!', 'disabled', $tmpl);
} else {
$tmpl = str_replace('!message!', '<font color=red>' . $err . '</font>', $tmpl);
$tmpl = str_replace('!disable!', '', $tmpl);
}
echo $tmpl;
exit;
}
function sendMail($title, $name, $email, $org, $body) {
global $upfile, $upfile2;
//認証情報
$host = "smtp.lolipop.jp";
$smtp_user = "fujii@mori1-hakua.tokyo";
$smtp_password = "パスワード";
$from = "fujii@mori1-hakua.tokyo";
$port = 465;
$ssl_type = "ssl";
$mail = new PHPMailer(true);
try {
$mail->IsSMTP();
$mail->SMTPAuth = true;
// $mail->SMTPDebug = 2; //デバッグなどを行うときはコメントアウトを解除!
$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false, //SSLサーバー証明書の検証を要求するか(デフォルト:true)
'verify_peer_name' => false, //ピア名の検証を要求するか(デフォルト:true)
'allow_self_signed' => true //自己証明の証明書を許可するか(デフォルト:false、trueにする場合は「verify_peer」をfalseに)
)
);
$mail->CharSet = "utf-8";
$mail->Encoding = "base64";
$mail->setLanguage('ja', '../../PHPMailer/language/');
$mail->SMTPSecure = $ssl_type;
$mail->Host = $host;
$mail->Port = $port;
$mail->IsHTML(false);
$mail->Username = $smtp_user;
$mail->Password = $smtp_password;
$mail->SetFrom($smtp_user);
$mail->From = $from;
$mail->FromName = mb_encode_mimeheader($name, "JIS", "UTF-8");
$mail->Subject = mb_encode_mimeheader($title, "JIS", "UTF-8");
$mail->Body = $body."\n".$upfile.' '.$upfile2;
$mail->setFrom($from, '在京白堊会事務局');
$mail->addAddress($email, $name);
$mail->addReplyTo($org, '年次幹事');
if ($upfile) {
$mail->addAttachment("../temp/$upfile");
}
if ($upfile2) {
$mail->addAttachment("../temp/$upfile2");
}
$mail->send();
return ' Successful';
} catch (Exception $e) {
return " Mailer Error: {$mail->ErrorInfo}";
}
}
// 投稿キーの生成と検証用関数
function generateKey($length = 6) {
$characters = '0123456789';
$key = '';
for ($i = 0; $i < $length; $i++) {
$key .= $characters[mt_rand(0, strlen($characters) - 1)];
}
return $key;
}
function checkKey($input, $crypt, $lifetime = 600) {
$now = time();
$expire = $now - $lifetime;
$data = @unserialize($crypt);
if ($data !== false && $data['time'] >= $expire && $data['key'] === $input) {
return true;
}
return false;
}?>