C# を PowerShell で実行 : メッセージボックスの応答結果をファイルに書き込む ( バッチファイルで利用可能 )

まずは動作確認の為、VisualStudio でコードを完成させます。
using System;
using System.IO;
using System.Windows.Forms;

namespace MessageBoxConsole
{
	class Program
	{
		static void Main(string[] args)
		{
			// テンポラリフォルダのパスを取得
			string path = Environment.GetEnvironmentVariable("temp");

			// 書き込むファイルのフルパスを編集する
			string writePath = $@"{path}\_check_result";

			// MessageBox を表示する( System.Windows.Forms の参照が必要です )
			// ※ OK か Cancel のボタンが表示されます
			DialogResult check = MessageBox.Show("実行しますか?", "確認", MessageBoxButtons.OKCancel);
			using (StreamWriter sw = new StreamWriter(writePath, false))
			{
				// OK ならば、ファイルに 1 を書き込みます
				if (check == DialogResult.OK)
				{
					sw.Write("1");
				}
				// CANCEL ならば、ファイルに 0 を書き込みます
				else
				{
					sw.Write("0");
				}

				// ファイルを閉じます
				sw.Close();

			}
		}
	}
}

▼ System.Windows.Forms の参照


次に PowerShell のスクリプトを作成して C# のコードを実行させます。その為に、PowerShell でスクリプトの実行を許可する手順 で設定を済ませておきます。

msgbox.ps1
$code = @"
using System;
using System.IO;
using System.Windows.Forms;
public class MyClass {
	public static void Main() {

		// テンポラリフォルダのパスを取得
		string path = Environment.GetEnvironmentVariable("temp");

		// 書き込むファイルのフルパスを編集する
		string writePath = string.Format( @"{0}\_check_result", path );

		// MessageBox を表示する( System.Windows.Forms の参照が必要です )
		// ※ OK か Cancel のボタンが表示されます
		DialogResult check = MessageBox.Show("実行しますか?", "確認", MessageBoxButtons.OKCancel);
		using (StreamWriter sw = new StreamWriter(writePath, false))
		{
			// OK ならば、ファイルに 1 を書き込みます
			if (check == DialogResult.OK)
			{
				sw.Write("1");
			}
			// CANCEL ならば、ファイルに 0 を書き込みます
			else
			{
				sw.Write("0");
			}

			// ファイルを閉じます
			sw.Close();

		}

	}
}
"@

Add-Type -Language CSharp -TypeDefinition $code -ReferencedAssemblies ("System.Windows.Forms")

[MyClass]::Main()


テキストファイルに結果を出力しているので、以下のようなバッチファイルで利用する事ができます
echo off

echo 処理を開始しました

powershell .\msgbox.ps1

FOR /F %%i IN (%temp%\_check_result) DO (
	if "%%i"=="1" goto :ok
	if "%%i"=="0" goto :cancel
)

:ok
echo OK を選択しました
goto :end

:cancel
echo Cancel を選択しました
goto :end


:end





PowerShell でスクリプトの実行を許可する手順

まず、PowerShell のスクリプトを作成して以下の内容を書き込みます

open-cur.ps1

$PSVersionTable
start .
start は、Start-Process のエイリアスで、この記述ではカレントフォルダをエクスプローラで開きます ( $PSVersionTable はバージョンの表示です ) スクリプトを保存したフォルダをエクスプローラで選択し、SHIFTキーを押しながら右クリックして『PowerShell ウインドウをここに開く』を選択します。 初期状態ではスクリプトの実行が許可されていないので、.\open-cur と入力してエラーが出る事を確認してから、ウインドウキー + I で設定ウインドウを開いて『更新とセキュリティ』を選択します。左サイドの内容の一覧から『開発者向け』を選んでかせ右サイドを一番したまでスクロールします。 PowerShell のスクリプトの実行が許可されていない場合は、チェックボックスが青色になっているのでその下の『適用』ボタンをクリックしてチェックボックスが灰色になれば設定は完了です。 .\open-cur と再度入力して結果を確認します 設定を元に戻すには 管理者権限で PowerShell のウインドウを開く必要があるので、CTRL + SHIFT で現在開いている PowerShell のウインドウのタスクバーのアイコンをクリックします。そして、以下のコマンドを入力してください
Set-ExecutionPolicy Restricted -Scope CurrentUser -Force
設定を変更せずにスクリプトを実行するには 以下の内容を書き込んだバッチファイルを作成して、バッチファイルにスクリプトの名前部分を渡して実行できます
@powershell -NoProfile -ExecutionPolicy Unrestricted "./%1.ps1"
PowerShell ウインドウでは、ps.bat スクリプト名 コマンドプロンプトでは ps スクリプト名 で実行できます

VBScript : 既存の Excel を PDF に変換する ( ExportAsFixedFormat )



単純な一覧データを出力した PDF の見本




Excelで名前を付けて保存で PDF に保存できますが、これはスクリプトで行うコードです。
( プリンタが使える状態でないと動作しません )

ExportAsFixedFormat メソッド

XlFixedFormatType

.wsf で作成しています。もともと、.wsf のほうが簡単に外部ライブラリを参照したり、オブジェクトを最初から定義できるのでコードが簡潔になります。ここでは、Excel.Application 内で定義されている定数も参照して使えるようにしています。

Excel 側では、印刷設定により一行目のタイトルを常に表示するようにしたり、A4 横にして縮小したりしています。シートは二つありますが、PDF に変換すると全て出力されます。


<JOB>
<OBJECT id="Fso" progid="Scripting.FileSystemObject" />
<OBJECT id="ExcelApp" progid="Excel.Application" />
<REFERENCE guid="00020813-0000-0000-C000-000000000046" />
<SCRIPT language="VBScript">
' Wscript.Echo xlTypePDF,xlTypeXPS

' **************************************
' スクリプトのあるディレクトリの取得
' **************************************
strCurPath = WScript.ScriptFullName
Set obj = Fso.GetFile( strCurPath )
Set obj = obj.ParentFolder
strCurPath = obj.Path

' 途中で異常終了すると、Excel がプロセスに残ってしまうので表示させています。
' マウス等で Excel 本体を操作しないで下さい。
' Excel を表示させたくない場合は、以下を削除または行頭に ' でコメントにして下さい
ExcelApp.Visible = True

Dim MyBook
Dim FilePath

' ここで Excel を参照するダイアログが開きます
FilePath = ExcelApp.GetOpenFilename("Excel ファイル (*.xlsx;*.xls), *.xlsx;*.xls", 1, "Excel ファイルの選択") 
if FilePath = "False" Then 
	MsgBox "Excel ファイルの選択がキャンセルされました"
	' スクリプト終了
	Wscript.Quit()
End If

' ここで Excel に読み込んでいます
on error resume next
' Workbook を取得( スクリプトと同じディレクトリ )
Set MyBook = ExcelApp.Workbooks.Open( FilePath )
if Err.Number <> 0 then
	' 終了( 開放 )
	ExcelApp.Quit()
	Wscript.Echo Err.Description & vbCrLf & FilePath
	' スクリプト終了
	Wscript.Quit()
end if
on error goto 0

Dim aPath
Dim strFileName
Dim aExt

' Excel の名前部分を取り出して、pdf の名前部分にします
aPath = Split(FilePath, "\")
strFileName = aPath(Ubound(aPath))
aExt = Split(strFileName,".")
strFileName = aExt(0)

' スクリプトと同じフォルダに保存されます
Call MyBook.ExportAsFixedFormat( xlTypePDF, strCurPath & "\" & strFileName & ".pdf" )

' 終了( 開放 )
ExcelApp.Quit()

' 終了確認
Wscript.Echo "処理が終了しました"

</SCRIPT>
</JOB>


Microsoft の記事

Application.GetOpenFilename メソッド

Microsoft の英文の記事

Saving Workbooks to PDF and XPS Formats in Excel 2007




VBScript : キーストロークを送信してキー操作をした事にする( 例 : リモート デスクトップ接続ダイアログ )

リモート デスクトップ接続は開いた後、詳細画面が表示されないので、ALT+O を送り、その後 SHIFT+TAB でタブを選択して、右矢印で次のタブに移動させます。 ALT+O SHIFT+TAB > 右矢印 画面タブで設定
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run( "mstsc.exe" )

WScript.Sleep(500)
WshShell.AppActivate("リモート デスクトップ接続")
WScript.Sleep(500)

' キーストロークを送信
WshShell.SendKeys ("%O")
WScript.Sleep(500)
WshShell.SendKeys ("+{TAB}")
WScript.Sleep(500)
WshShell.SendKeys ("{RIGHT}")

※ キーストロークの送信は環境や状況によっては、うまく動作しないかもしれません。その場合は適宜変更して下さい (キーストローク詳細 / SendKeys メソッド)




VBScript : ファイルのパスや名前をクリップボードへ( ダブルクォートなし ) / 送るフォルダに保存

エクスプローラで、SHIFT キーを押しながら右クリックすると『パスとしてコピー』がありますが、ダブルクォートが付加されています( たいていはそのほうがいいのですが )ので、ダブルクォートのないパスを取得します


▼ こんな感じで取得されます
"C:\Program Files\7-Zip\7-zip.dll"

filepath.vbs( SendTo ディレクトリに置いてください )

Set WshShell = Wscript.CreateObject("WScript.Shell")
Set Fso = Wscript.CreateObject("Scripting.FileSystemObject")

strTemp = WshShell.ExpandEnvironmentStrings("%temp%")
strPath = strTemp & "\__clipCommand.tmp"

Set objHandle = Fso.OpenTextFile( strPath, 2, True )
objHandle.Write Wscript.Arguments(0)

Call WshShell.Run( "cmd.exe /c clip < """ & strPath & """", 0, True )
▼ こうなります
C:\Program Files\7-Zip\7-zip.dll

以下はディレクトリ部分を省いた名前の部分のみをクリップボードにコピーします。

filename.vbs( SendTo ディレクトリに置いてください )

Set WshShell = Wscript.CreateObject("WScript.Shell")
Set Fso = Wscript.CreateObject("Scripting.FileSystemObject")

strTemp = WshShell.ExpandEnvironmentStrings("%temp%")
strPath = strTemp & "\__clipCommand.tmp"

Set objHandle = Fso.OpenTextFile( strPath, 2, True )
strName = Wscript.Arguments(0)
aPath = Split(strName,"\")
strName = aPath(Ubound(aPath))
objHandle.Write strName

Call WshShell.Run( "cmd.exe /c clip < """ & strPath & """", 0, True )

▼ こうなります
7-zip.dll

さらに以下では、複数ファイルを選択した場合のファイル名部分だけを取り出して複数行としてコピーします( 但しあまり大量のファイルは元々の文字列の制限によりエラーとなります

filelist.vbs( SendTo ディレクトリに置いてください )

Set WshShell = Wscript.CreateObject("WScript.Shell")
Set Fso = Wscript.CreateObject("Scripting.FileSystemObject")

str = ""
For I = 0 to Wscript.Arguments.Count-1
	aData = Split( Wscript.Arguments(I), "\" )
	str = str & aData(Ubound(aData)) & vbCrLf
Next

strTemp = WshShell.ExpandEnvironmentStrings("%temp%")
strPath = strTemp & "\__clipCommand.tmp"

Set objHandle = Fso.OpenTextFile( strPath, 2, True )
objHandle.Write str
Call WshShell.Run( "cmd.exe /c clip < """ & strPath & """", 0, True )

▼ ファイルが多すぎて起きるエラー


▼ うまくいくとこんな感じです
nslookup.exe
ntdll.dll
odbc32.dll
ole32.dll


操作補足

エクスプローラで SendTo フォルダに移動するには、アドレスバーに sendto と直接入力します。テンポラリフォルダは、%temp% と入力して下さい。




コードを直接ダウンロードした場合は、右クリックのプロパティより『許可する』にチェックしておきます。






Google Chrome をシークレットモードで指定URLを起動時に表示させる

⭐ 以下の内容でショートカットを作成します。
( https://www.google.co.jp/ の部分は最初に表示したい URL を指定します )
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --incognito https://www.google.co.jp/
▼ パスの取得方法です


さらにこのショートカットをスタートアップにコピーする事もできます。

スタートアップフォルダは、エクスプローラのアドレス部分に『sendto』と入力し、一つ上に上がって『スタートメニュー』に入り、『プログラム』>『スタートアップ』です

C:\Users\ユーザID\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
shell:startup か コマンドプロンプト(または PowerShell)で start shell:startup でも開きます VBScript でスタートアップフォルダ開くコードは以下のようになります
Set obj = CreateObject("Shell.Application")
Set objFolder = obj.NameSpace( &h7 )
obj.Explore(objFolder.Self.Path)


▼ 以下は PowerShell で開く方法です
powershell start $([Environment]::GetFolderPath(7))

他の特別なフォルダ番号はここから参照してください




コマンド リダイレクト演算子を使用する( Using command redirection operators )

✅ Microsoft ドキュメント
コマンド リダイレクト演算子を使用する

⭐ 単純な リダイレクト は > です。
 コマンドプロンプトに表示されるはずの文字列をファイルに書き込みます。

⭐ >> を使うと追加書き込みです。

このような記号は、リダイレクト演算子と呼ばれます。

STDIN

0

キーボード入力

STDOUT

1

標準出力

標準エラー出力

2

Error output to the Command Prompt window

0、1、2 は ハンドル番号で、既存のハンドルへのリダイレクトを指定するには、アンパサンド(&)文字の後にリダイレクトしたいハンドル番号を使用します。

なので、2>&1 は 標準エラー出力を標準出力にリダイレクトする事を意味します。

▼ 解りやすいテストはエラーだけに着目して、以下のように実行します。
C:\temp>dir x
 ドライブ C のボリューム ラベルは Windows10 です
 ボリューム シリアル番号は 40B9-7D17 です

 C:\temp のディレクトリ

ファイルが見つかりません
( x が存在しないので『ファイルが見つかりません』と言うエラーメッセージが出ます ) この『ファイルが見つかりません』は、dir x > message.txt としても message.txt には書き込まれまれずに、コマンドプロンプトに表示されます。 しかし、以下のようにすれば全て書き込む事ができます。
dir x > message.txt 2>&1
この方法は解りにくいですが、標準出力と標準エラー出力を同時にリダイレクトしたいときに意味があります。
dir x 2> message.txt
だと、ファイルが見つかりません だけが書き込まれてしまいます。 キーボード入力をファイル化 リダイレクト演算子を使用して、キーボードから入力した文字列をテキストファイルに書き込む事ができます。
type con > message.txt
type コマンドは、ファイルの内容をコマンドプロンプトに表示するコマンドですが、con と言う特殊な予約文字列を使用すると、キーボードをファイルとみなした動作を行います。 ※ 終了時は 改行入力後、CTRL+Z を入力してEnter です 空のファイルを作成する nul と言う予約文字列を使用して以下のように実行します
type nul > message.txt
実行結果を表示しない nul は存在しないファイルのようなものなので、標準結果への出力を無かった事にできます
dir *.* > nul
エクスプローラで作成できないファイルを作成する .(ドット) で始まるファイルはエクスプローラで作成できませんが、以下のようにすれば作成する事ができます
type nul > .htaccess
| (パイプ) で標準出力を標準入力に受け渡す sort コマンドは、標準入力をソートします。その際、標準入力へ渡す方法の一つとして |(パイプ) があります。
dir | sort
このようにすると、ソートした結果が表示されます。この際、データが多いと内容が一気に表示されてしまいます。この時、CTRL+S キーで一旦停止する事ができますが以下のようにすると表示できる単位で一旦停止をする事ができます。
dir | sort | more
続きはスペースキーで参照し、強制終了は CTRL + C となります。 < (リダイレクト入力) で標準入力にデータを渡す パイプ以外にも、標準入力のあるプログラム < ファイルのパス で標準入力にファイルの内容を直接渡す事ができます
sort < message.txt

C# で使用する SQL 文を外部テキストにして String.Format でデータ部分を置き換えて利用する

基本的には、String.Format メソッドのお話ですが、文字列の配列の扱い(ListArrayList)や正規表現のオプションと置換方法が注意事項です。
-- ******************************
-- 社員マスタ更新
-- ******************************
 
UPDATE 社員マスタ
set
氏名 = '{1}',
給与 = {2},
-- 行コメント
生年月日 = {3}

--
 
where 社員コード = '{0}'
 
-- 行コメント

行コメントは、正規表現で削除します。{} 部分の個数より、配列が大きい必要があり、Nothing が指定されると、{} ごとなくなります。
※ 配列のリサイズが必要な場合は、Array.Resize メソッドで行います。

オンラインの正規表現テストツール

(?m) は複数行モードのオプションです。m に対して s だと単一行モードになります
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace text_input
{
	class Program
	{
		static void Main(string[] args)
		{
			// 入力ファイルのパス
			string[] arguments = Environment.GetCommandLineArgs();
			// 引数は一つのみ許可
			if (arguments.Length != 2)
			{
				Console.WriteLine("引数を指定して下さい");
				return;
			}

			// 引数から取得
			string filePath = arguments[1];

			// パスを表示
			Console.WriteLine(filePath);

			// *********************************
			// ▼ 関数呼び出しを記述して、ALT + Enter で自動作成
			// *********************************
			string textData = loadTextData(filePath);

			// *********************************
			// 行コメントの削除
			// ▼ 正規表現のオプション
			// https://docs.microsoft.com/ja-jp/dotnet/standard/base-types/regular-expression-options
			// *********************************
			string pattern = "(?m)^--.*";   // 複数行モード
			textData = System.Text.RegularExpressions.Regex.Replace(textData, pattern, "");

			Console.Write(textData);

			// *********************************
			// 配列の準備(1)
			// *********************************
			string[] data1 = { "0001", "山田太郎", "100000", "'1980/01/01'" };
			Console.WriteLine("配列の数は {0} です", data1.Length);

			// *********************************
			// 配列を文字列内に埋め込む
			// *********************************
			string sqlResult = String.Format(textData, data1);
			Console.Write(sqlResult);

			// *********************************
			// 配列の準備(2)
			// *********************************
			string[] data2 = new string[4];
			data2[0] = "0002";
			data2[1] = "山田花子";
			data2[2] = "20000";
			data2[3] = "NULL";

			// *********************************
			// 配列を文字列内に埋め込む
			// *********************************
			sqlResult = String.Format(textData, data2);
			Console.Write(sqlResult);

			// *********************************
			// 配列の準備(3)
			// *********************************
			string[] data3 = new string[4];
			data3.SetValue("0003", 0);
			data3.SetValue("山田美子", 1);
			data3.SetValue("30000", 2);
			data3.SetValue("'1980/01/01'", 3);

			// *********************************
			// 配列を文字列内に埋め込む
			// *********************************
			sqlResult = String.Format(textData, data3);
			Console.Write(sqlResult);

			// *********************************
			// 配列の準備(4)
			// *********************************
			List<string> data4 = new List<string>();
			data4.Add("0004");
			data4.Add("山田史郎");
			data4.Add("40000");
			data4.Add("'1990/01/01'");

			// *********************************
			// 配列を文字列内に埋め込む
			// *********************************
			sqlResult = String.Format(textData, data4.ToArray());
			Console.Write(sqlResult);

			// *********************************
			// 配列の準備(5)
			// ※ 追加するデータ型自由
			// *********************************
			ArrayList data5 = new ArrayList();
			data5.Add("0005");
			data5.Add("山田吾郎");
			data5.Add(50000);
			data5.Add(new DateTime(1995, 1, 1));

			// *********************************
			// 配列を文字列内に埋め込む
			// 混在なので object 配列
			// *********************************
			object[] strWork = data5.ToArray();
			sqlResult = String.Format(textData, strWork[0], strWork[1], strWork[2], $"'{strWork[3]}'");
			Console.Write(sqlResult);

			Console.ReadLine();

		}

		private static string loadTextData(string filePath)
		{

			string text = "";

			// *********************************
			// 主なエンコード
			// *********************************
			// SHIFT_JIS
			// Encoding Enc = Encoding.GetEncoding(932);
			// EUC-JP
			//Encoding Enc = Encoding.GetEncoding(51932);
			// UNICODE 用
			//Encoding Enc = Encoding.GetEncoding(1200);
			// UTF-8N
			Encoding Enc = new UTF8Encoding();
			// UTF-8
			//Encoding Enc = new UTF8Encoding(true);

			// プロック終了時に開放
			try
			{
				using (StreamReader ReadFile = new StreamReader(filePath, Enc))
				{
					// 読込み
					text = ReadFile.ReadToEnd();

					// 全て読み込んでいるので閉じる
					ReadFile.Close();

					Console.Write(text);
				}

			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.Message);
			}

			return text;

		}
	}
}


関連する記事

C# : シンプルなテキストファイルの一括入力 / ReadToEnd() : VS2017




PHP : mysqli を使用した単純な問合せアプリケーション

ダウンロード

▼ デモページ

データベースの接続に必要な値は、include_path に設定されたディレクトリに config.php を作成してセットします

▼ config.php
<?php
$host = "MySQLサーバ";
$user = "ユーザ";
$pass = "パスワード";
$db = "データベース";
?>
control.php ( エントリポイント )
<?php
# ***************************
# ソースベースの取り込み
# ***************************
require_once('settings.php');
require_once('model.php');
require_once('config.php');

# ***************************
# MySQL 接続
# ***************************
$con = @new mysqli($host, $user, $pass, $db);
$con->set_charset("utf8");

# ***************************
# MySQL 用特殊文字エスケープ
# ***************************
foreach( $_REQUEST as $key => $value ) {
	$_REQUEST["db"][$key] = $con->real_escape_string($value);
}

# ***************************
# テーブル表示
# ***************************
build_table($con);

# ***************************
# MySQL 接続解除
# ***************************
$con->close();

# ***************************
# 画面定義
# ***************************
require_once('view.php');
?>



view.php ( 画面定義 )

<?php
# **************************************
# js キャッシュ用
# **************************************
$tm = mktime();

# **************************************
# 画面定義
# ( Ruby や Python に合わせた画面形式 )
# **************************************
$out_client = <<<HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="width=device-width initial-scale=1.0 minimum-scale=1.0 maximum-scale=1.0 user-scalable=no" name="viewport">
<title>MySQL 問合せ</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.css" />

<script src="entry.js?{$tm}"></script>

<style>
body {
	margin: 0;
}

#main {
	padding: 0px 16px 3px 16px;
}

</style>
</head>
<body>
<div class="alert alert-dark">
	簡易タイトル
</div>
<div id="main" class="table-responsive">

	<table class="table table-hover">
	{$GLOBALS['table']}
	</table>

</div>
</body>
</html>
HTML;

print $out_client;


?>


model.php ( HTML 作成部分 )
<?php
# ***************************
# モデル用関数を定義する
# ***************************

# ***************************
# テーブル表示
# ***************************
function build_table($con) {

	// デバッグ用
	file_put_contents("debug.log", "build_table:開始\n" , FILE_APPEND );
	file_put_contents("debug.log", print_r( $con ,true ) , FILE_APPEND );

	// TR 内の HTML 文字列
	$lines = "";
	$sql= <<<SQL
		select 
			社員コード,
			氏名,
			フリガナ,
			所属,
			性別,
			作成日,
			更新日,
			給与,
			手当,
			管理者,
			DATE_FORMAT(生年月日,'%Y/%m/%d') as 生年月日
		from 社員マスタ
		where 氏名 like '%{$_REQUEST["db"]["nm"]}%'
SQL;

	$rs = $con->query($sql);	// エラー処理省略(本当は必要)
	//  デバッグ用
	file_put_contents("debug.log", print_r( $rs ,true ) , FILE_APPEND );

	// 列情報を取得( タイトル用 )
	$fields_data = $rs->fetch_fields();
	foreach( $fields_data as $field ){
		$lines .= "<th>{$field->name}</th>";
	}

	// 列データを取得
	while( $row = $rs->fetch_array(MYSQLI_BOTH) ) {
	
		$cells  = "";
		for( $i = 0; $i < $rs->field_count; $i++ ) {
			$cells .= "<td>{$row[$i]}</td>";
		}
	
		$lines .= "<tr>{$cells}</tr>" . "\n";
	}

	// 埋め込み用グローバル変数へセット	
	$GLOBALS['table'] = $lines;

	//  デバッグ用
	file_put_contents("debug.log", "build_table:終了\n" , FILE_APPEND );

}


?>


settings.php ( 共通設定 )
<?php
// ***************************
// 共通処理( UTF8N で保存 )
// ***************************
error_reporting( E_ALL & ~E_NOTICE & ~E_STRICT );
ini_set('display_errors', '1');
ini_set('date.timezone', 'Asia/Tokyo');
ini_set('default_charset', 'utf-8');
session_cache_limiter('nocache');
session_start();
header( "Content-Type: text/html; charset=utf-8" );


foreach( $_REQUEST as $key => $value ) {

# ここで $_REQUEST 内の文字列のセキュリティ上の処理

}

# デバッグログの初期化
file_put_contents("debug.log", "開始\n" );

# メッセージ
$check_message = "";

# クライアントコントロール
$pass = "1";
?>





clipboard.js を使用して WEBページ上でテキストをクリップボードにコピーする

clipboard.js
CDNJS

デモページ

ページ下部は、div に contenteditable="true" を設定しているので直接編集できるエリアになっています。なので、クリップボードにコピーした後は普通に貼り付けて確認できます。

実装内容

1) ページにひとつだけ、クリップボード転送用の要素を DIV で作成します(ここでは id="clipboard")
   (body 要素直下でいいと思います)

2) DIV 内に改行やスペースを反映させる為に white-space:pre-wrap を設定する
( 3) で幅を指定してそこで改行させる為の -wrap を使用します )

3) ページ上から隠す為に、position:absolute;left:-1000px を設定する
   (クリップボートへコピーする為に選択する必要があるので、非表示では動作しません)
   転送したテキストがこちら側へ表示しないように width:900px と word-wrap:break-word を指定する

4) クリックイベントは、ボタンである必要は無く、どのような要素でも良い

5) ここでは、クリップボードへコピーが終了した後、alert でメッセージを表示しています
( 必要な場合にこのようにイベントを使用します )

注意事項

ここでは、WEB ページ内に無い文字列を加工等してクリップボードに転送する事を想定しているので、転送用の隠し DIV を用意していますが、WEB ページ上に既にあるテキストならば、その要素に対して直接 data-clipboard-target 属性をトリガー要素に設定します


<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="width=device-width initial-scale=1.0 minimum-scale=1.0 maximum-scale=1.0 user-scalable=no" name="viewport">
<title>クリップボードへコピー</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.css" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.4/clipboard.min.js"></script>

<script>
$(function(){

	// ***************************
	// クリップボード
	// ***************************
	// コピーする時のトリガーとなる要素に設定されるクラスを決定
	var clipboard = new ClipboardJS('.clip_trigger');

	// ***************************
	// コピー成功後のイベント
	// ***************************
	clipboard.on('success', function(e) {
		alert("クリップボードにコピーしました");
	});

	// ***************************
	// クリップボード用データ転送
	// ***************************
	$("#act_copy").on("click", function(){

		$("#clipboard").text( $("#text_data").val() );

	});

});

</script>

<style>
html,body {
	height: 100%;
}

body {
	margin: 0;
}

#text_data {
	width:300px;
}

/* 上下エリア フィットコントロール用  */
#head {
	padding: 16px;
	width: 100%;
	height: 230px;
}
#extend {
	padding: 4px 16px;
	border: solid 2px #c0c0c0;
	overflow: scroll;

	margin-left: auto;
	margin-right: auto;
	width: calc( 100% - 3px );

	height: calc( 100% - 230px - 2px );
}

</style>

</head>
<body>
<!-- クリップボード用隠しエリア -->
<div id="clipboard" style='position:absolute;left:-1000px;width:900px;white-space:pre-wrap;word-wrap:break-word;'></div>
<div id="head">
	<div class="alert alert-primary">クリップボード処理
	<a class="btn btn-secondary btn-sm float-right align-top" href=".">フォルダ</a>
</div>

	<span class="align-top mr-4">クリップボードへコピー</span>

	<textarea class="align-top mr-4" id="text_data"></textarea>

	<input
		id="act_copy"
		data-clipboard-target="#clipboard"
		class="clip_trigger btn btn-primary align-top mr-4"
		type="button"
		value="実行">

	<input
		onclick="location.reload(true)"
		class="btn btn-info btn-sm align-top  mr-4"
		type="button"
		value="再表示">


</div>

<!-- 編集可能なエリア : ここにクリップボードの内容を貼り付けて確認する -->
<div id="extend" contenteditable="true"></div>



</body>
</html>