SendmailからPHPmailerへの移行

平文でメール発信していたツールを、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によるプログラム

これで、Gmailにも正確に届く。

カテゴリー: お知らせ | コメントする

2023年は、4,733,320歩でした!

カテゴリー: お知らせ | コメントする

2x2キューブの簡易攻略法

ボケる前に、2x2の最終簡易攻略法を記録しておく。
1)白パーツを雑に下段に集める
2)下段から上段に規律良くパーツを移し、白完全一面を作る
  ・最初は青がターゲット
  ・上段左上の色のパーツを右上に持ってくる
   ・右下直下に現れたら、L’F L
   ・直下底側に現れたら、B R B’
   ・左下に現れたら、R’ D2 R 後、直下底から B R B’
  上側を90°回転し、4個実施したら、完全一面を確認する
  本規律が実際にありがたいのは、最後の1個の時だけかもしれない。
3)下段の黄色パーツの4つ角の位置合わせをする
  隣接交換または、対角交換が1組必要になっている。
  隣接交換:X U’R U L’U’R’U R U
  対角交換:X2 R’U’F’U F R U
4)下段の黄色パーツの黄色の向きを下面に合わせる
  ・下段右下に来たパーツが、黄色横向きなら、
    セクシームーブ:R U R’ U’
  ・下段右下に来たパーツが、黄色手前向きなら、
    逆セクシームーブ:U R U’ R’
5)黄色完全一面を確認し、横回転で上段と面を合わせ完成!

シミュレーションツール、「お告げNavi」は次のURL.

https://mori1-hakua.tokyo/CubeV4/navigation-22to44.html


  

カテゴリー: お知らせ | コメントする

2022年間歩行数・4,196,753歩

カテゴリー: お知らせ | コメントする

Androidでの自動運転

白堊芸術祭で、初めての試みとしてアプリ・デモの動的展示を実施した。
Windowsでは難なくセットアップできるアプリの自動起動・Shutdownが
Androidではコツが必要だったので、ボケる前に記録しておく。

1)自動電源ON/OFF
  Androidの version10あたりから、システム設定画面に次の項目が登場
  している。
  「自動電源オン/オフ」
  それぞれの時刻を設定し、Activeにしておけばよい。
  なお、オフ中であっても夜中などに、「充電完了」を報告しようとして
  勝手に電源が入るので、要注意!

2)アプリの自動起動/シャットダウン
  システムの設定にもデフォルトアプリの設定があるが、これは常駐設定の
  ことなので、趣旨が違っている。
  そこで、自動運転のためには、著名なMacroDroidアプリをインストールする。
  設定内容について、画面コピーを貼り付けておくことにする。

カテゴリー: お知らせ | コメントする

CLOVER-USB版でのWindows11稼働

CLOVER-USB版でのWindows11稼働と、その後の手続きを説明する。

1.NVMe SSDを設置後、NVMeではないSSD/HDDからの旧Windows起動
  なお、ESP(EFI System Boot Partition)は、ここに作成する。
  GPTタイプで、Windows partition前に500MB程度の空き領域があると良い。
2.Rufusのインストール
  https://forest.watch.impress.co.jp/library/software/rufus/
3.Rufusの起動
  ここまでは、CLOVERのインストールで実施済みの作業なので、同様に。
4.Windows11のダウンロード
  「ブートの種類」の「選択」の横の▼マークをクリックし、ダウンロード
  を選択する(オプション設定でUPDATE確認なしだと、マークは出ない)。
  ・その後、「ダウンロード」をクリックする。
  ・バージョンの選択Popupで、「Windows11」を選択し「続ける」。
  ・リリースの選択が追加されるので、「最新のもの」を選択し「続ける」
  ・エディションの選択が現れるので、そのまま「続ける」
  ・「ダウンロード」ボタンが表示されたら、8GB以上の空きのある所に
   ダウンロードを実施する。
5.Windows11のインストール媒体作成
  ・ダウンロードが完了すると、ブートの種類には、ダウンロードした
   ISOイメージファイルが表示されている。
  ・デバイス欄で、インストールに用いるUSBメモリが表示されている。
  ・イメージオプションが、(TPM2.0)になっているので、プルダウンから
   Extended windows(NoTPM)を選択する。
  ・パーティション構成を「GPT」とし「スタート」をクリックして、
  インストール媒体を作成する。

6.Windows11のインストール
  ・NVMe以外のドライブにESPを確実に設置することが肝要なので、ESP
   パーティションの場所を確認する。
  ・作成されたUSBメモリからBootし、インストールを実施する。
   WindowsのインストールISOファイルには、NVMeドライブへのドライバー
   も搭載されているので、インストール先にNVMeドライブを指定できる。
   インストール中に再起動されると、NVMeドライバーなしの状態で一時域
   をアクセスするので、最初の再起動のタイミングで、CLOVERのUSBメモリ
   に差し替える。
  ・インストール先の全領域は、diskpart→ list volume→ select volume→
   clean のあと、convert gpt コマンドで初期状態にしておく。
  ・インストール・プロセスをすべて完了したら、次のコマンド群を投入して、
   ESPに従来のOSを追加登録することもできる。
   OS本体のパーティションコピーを実施後、
   diskpart→ list volume
    (下記コマンドで使うパーティション文字がわかる)
   bcdedit /copy {current} /d “新しい識別文字列(Windows10NVMなど)”
   diskpart→ list volume→ select volume→ uniqueid volume
      (COPYしたOSボリューム・エントリのIDがわかる)
   bcdedit /set 獲得ID device partition=xx: 
   bcdedit /set 獲得ID osdevice partition=xx: 
  ・CLOVER-USB起動から、CLOVERのWindows EFI Boot from EFIを選択して
   Windows11などのOS立ち上げ動作を確認する。

7.CLOVER Boot Loaderの旧Windowsドライブへの搭載
  毎回USBメモリからのWindows起動だと耐久性が心配なので、旧Windowsを
  入れたESPのあるドライブにCLOVER本体を入れ、先頭Bootmgrにリンクする。
   bcdedit /set “{bootmgr}” path \EFI\CLOVER\CLOVERX64.efi
  このリンクは新規にWindowsインストールを実施するごとにもとに戻される
  ので、その都度、再設定する。
  ESPに diskpart→ select volume→ assign letter=S などでドライブレター
  を割り当てるが、Explorerでは管理者モードでもアクセス出来ないので、
   xcopy /e xxxxxx\CLOVER S:\EFI\CLOVER
  のコマンドを管理者コンソールから投入する。

8.USBドライブなしの動作を確認

  USBを差し込まなくても、そのままNVMeドライブの起動を含むアクセスが
  問題ないことを確認する。
  BIOS設定画面では、起動順位の1番が「Windows Boot Manager」と設定されて
  いるが、7.の手順で、次のコマンドを入力しておくと、その記述名に
  変更されて設定されるのでわかりやすい。
   bcdedit /set “{bootmgr}” description “Clover Boot Manager”

なお、再インストールの場合は、USBからのBootにしておく必要がある。


                               以上

カテゴリー: お知らせ | 4件のコメント

PCへのNVMe-SSDの取り付けと設定手順

スロットのないPCへのNVMe-SSDの取り付けと設定手順

1.Storageのパーティション方式は、MBRの世界からGPTの世界へ大変身
2.PCデバイスは、どのようにBootパーティションを辿るか
  NVRAM(不揮発)のエントリーからBoot Managerを探す。
  (bcdedit /enum firmware で定義が見える。例では、MBRやGPTハードの存在定義)
   ファームウェアのブート マネージャー
   ——————————–
   identifier {fwbootmgr}
   displayorder {bootmgr}
    {0210a6f8-841b-11ec-be14-806e6f6e6963}
    {f21ca4b8-83c9-11ec-9e05-806e6f6e6963}
    {338c29dd-8425-11ec-a441-001bdc0fee26}
   timeout 1
 ・MBRは歴史的遺産の方法で、ひたすらドライブの先頭セクターを探している
 ・GPT形式のUEFIだと、FAT32フォーマットのセクターをドライブ内に探す。
  4Kセクターサイズもあるため、最小260MBに及ぶ場合もある。
 ・SATA/AHCIに代わるNVMeプロトコルは、2018年以降の設計ハードでないと
  Firmドライバー未搭載で、ドライブの存在が見えない。
3.旧式マザーボードのNVMeドライブのためのドライバー後付け補給
 ・後付けには、旧式Bootファーム(ROM)への機能追加update と
  エミュレーション型Wrapperソフトの方式があるが、ROM Updateは限定品。
 ・Wrapperでは、フリーソフトのCLOVERが有名だが、USB Bootを標準としており、
  USBメモリの耐久性が心許ない。(USB Bootまでは、ここが参考になる)
4.CLOVERのHDD/SSDドライブへの搭載について
  BCDEDITコマンドで、{bootmgr}へCLOVERを定義する方法で、移行できる。
  CLOVER本体の登録は、EPSパーティションへのドライブレターの割り当て
  (DISKPARTコマンド)と、XCOPY /e コマンドの活用が鍵になる。
  (explorerを管理者モードで起動しても、アクセスはできない。)
5.マルチブートの定義
  すべてBCDEDITコマンドでEPSを保守実施するのが確実である。
  通常許されない、複数のEPSをCLOVERで切り替えながら運用することもできた。
6.コマンド・ログ
  ドライバー搭載とWindows11のマルチブートインストールを実施した実例

カテゴリー: お知らせ | 2件のコメント

本年もよろしくお願いします

https://www.facebook.com/photo/?fbid=4607435852656643&set=a.423777297689207

カテゴリー: お知らせ | コメントする

Raspberry Pi Picoでアナログ時計(原子精度)

MicroPythonで楽々プログラミング。十分に高速処理してくれます。
舐めてかかったら、色々、初心に帰ることに(笑い)。
1)UTC(グリニッジ)からLOCAL時間に+9時間・・・・
  桁上りが複雑だったのに、Simpleに組む方法を試行錯誤。
2)針が通過したところの絵を戻すのに、スプライトなんてものは
  無いから、針の汚したところを裏絵で描き戻し。
3)12時の通過時にたくさんの処理が集中しないように、分散化。
4)Core1も使ったスレッド処理を試みるもSMP-OSの無い中では、
  制限がきつい。
5)GPS情報に曜日は載らないので、計算するのね。
  def week(yy, feb):
    days = (125+yy[0]+yy[0]//4+int(“*033614625035″[yy[1]])+yy[2])
    wday = (days-1)%7 if feb==29 and yy[1]<3 else days%7
    return wday

などなど・・・

https://github.com/NorioFujii/GitPython/


カテゴリー: RaspberryPi, お知らせ | 1件のコメント

RaspberryPi Pico で 高度Lチカ 音の光出力

銭湯の料金1回分で買えるRaspberryPi Pico、恐ろしい能力を秘めていました。
専用ICチップ無しにSPDIFで音楽を光送出するのにも使えるPIO機能の装備は、
他の廉価マイコンボードに真似ができません。
Example Programとして用意されている、Sine波出力プログラムを
https://github.com/raspberrypi/pico-playground/tree/master/audio/sine_wave

アレンジして、好みの楽曲のWAVファイルから、高度Lチカによって光再生する
Cソースコードを生成し、コンパイルして書き込む手順をここに公開します。

表面実装タイプのボード1枚のまま、何も増設せずに再生できるように、Flash
2MBの範囲(10秒程度繰返し)で書き込めるサンプルプログラムとします。
Example ProgramのSine波の代わりにWAVファイルから取り出したPCMデータの
先頭から10秒程度を与える形のソースコード生成をツールで支援してくれます。

ソースコード生成のためにPythonプログラムを用意しています。
母艦はWindowsでもMacでもOKですが、ここではPico親類のRaspberry Pi3Bや4B
での操作例をハードコピーしています。

用意すべきWAVファイルは、16BitモードでMonoにフォーマット変換したリアルPCM
のものです。Stereoでの実装は、まだ少しチューニングが必要なようです。

1)ツールによるソースコード生成
(cmd)python3 uf2convWav.py -o sine_wave_spdif.c  -C 入力WAVファイル名
次の uf2convWav.py を実行することで、ソースコード sine_wave_spdif.c
が生成されます。
https://mori1-hakua.tokyo/test/uf2convWav.txt (拡張子変更)

2)Pico開発環境のセットアップ
クイック・セットアップとして紹介されている手順で整備します。
https://www.raspberrypi.org/blog/how-to-blink-an-led-with-raspberry-pi-pico-in-c/
blink.uf2 を作って書き込んでみるのは、いい予行演習になりますね。

3)sine_wave のアレンジ
2)の「cd pico/pico-examples」の代わりに「cd pico/pico-playground」と
入力し、お定まりの手順を実行し、配下のaudio/sine_wave に移動します。
mkdir build
cd build
cmake ..
make
次に、CMakeLists.txtのadd_executable(sine_wave_spdif sine_wave.c)を、
add_executable(sine_wave_spdif sine_wave_spdif.c)に替えます。
また、同じディレクトリ内に、1)で生成したsine_wave_spdif.cを追加します。

4)コンパイルしターゲットファイル作成
再び、buildディレクトリで、
cd build
cmake ..
make
によって、配下のaudio/sine_waveディレクトリに出力されたuf2ファイルを
確認します。(Flash2MBを超えても、平気で書き込むので要注意です)

5)Picoボードへの書き込み
Blinkプログラムと同様の方法です。
PicoボードのBOOTSELボタンを押したまま、母艦からのUSBケーブルを接続し、
次のCopyコマンドを実行します(ケーブル抜差しを避けるにはRUN端子を使う)。
cp build/audio/sine_wave/sine_wave_spdif.uf2 /media/pi/RPI*

6)オーディオ装置への光入力
Picoボードに5Vを供給、光デジタル入力のあるオーディオ装置で、入力形式を
PCMと設定し、光ケーブルの一方をPicoボードのLEDに近づけます。
GPIO12をGNDに落とせば、用意した楽音とサイン波とを交互に切り替えることが
出来ます。
なお、オーディオ装置の初期ボリューム設定には、十分に留意してください。

カテゴリー: RaspberryPi | 2件のコメント