- 生成AIで作成したCSVファイルをExcel(オンライン版)で開いたら、文字化けしてしまいました。
- そこで、文字列をShift-JISにエンコードして sjis.csvとしてダウンロードし直すためだけのオンラインツールを作りました。
1. ExcelはCSVの文字コードをShift-JISと過程する
生成AI(Claude)が出力した csvファイルをそのまま オンライン版のExcelで開いたら、文字化けしてしまいました。

これは、UTF-8のテキストファイルをShift-JISとして開いたことが原因です。
そこで、入力されたテキストをShift-JISのCSVファイルとしてダウンロードできるツールを作りました。

2. PHPコード(index.php)
ウェブベースのShift-JIS CSVエンコーダーツールを実装しました。
このコードでは、ユーザーが入力したテキストをShift-JISエンコードされたCSVファイルとしてダウンロードできるようにしています。
- POSTリクエスト処理:
テキストエリアと送信ボタンを含むフォームの送信処理を行います。 - エンコーディング変換:
入力テキストをUTF-8からShift-JISに変換します。
(mb_convert_encoding
関数) - ファイルダウンロード設定:
ヘッダーを設定し、CSVファイルとしてダウンロードさせます。
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$input_text = $_POST['input_text'];
// UTF-8からShift-JISへエンコード
$shift_jis_text = mb_convert_encoding($input_text, 'SJIS', 'UTF-8');
// ファイル名を設定
$filename = 'sjis.csv';
// ヘッダーを設定してファイルダウンロードを強制
header('Content-Type: text/plain');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Length: ' . strlen($shift_jis_text));
// エンコードされたテキストを出力
echo $shift_jis_text;
exit;
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Shift-JIS CSVエンコーダー</title>
</head>
<body>
<h1>Shift-JIS CSVエンコーダー</h1>
<p>Shift-JIS CSVエンコーダーは、Excelで開けるCSVファイルにするためのオンラインツールです。</p>
<form method="post">
<textarea name="input_text" rows="10" cols="50" placeholder="ここにテキストを入力してください"></textarea><br>
<input type="submit" value="Shift-JISでダウンロード(sjis.csv)">
</form>
</body>
</html>
3. 【追記】脆弱性対策
ただし、このままではいくつかのセキュリティ上の脆弱性があります。
- ヘッダーインジェクションの可能性
- メモリ制限の考慮不足
- XSS(クロスサイトスクリプティング)の脆弱性
Content-Disposition
ヘッダーで、ファイル名が適切にサニタイズされていません。- 改行文字などを含む悪意のあるファイル名が指定された場合、ヘッダーインジェクションの脆弱性につながる可能性があります。
- 入力テキストのサイズ制限がないため、大量のデータが送信された場合にメモリ不足が発生する可能性があります
- フォームから送信された
$input_text
がHTMLエスケープされずに出力されています。 - 攻撃者が悪意のあるスクリプトを含むテキストを送信することで、スクリプトが実行される可能性があります。
以下の対策を追加していきます。
- 入力サイズの制限(1MB)を設定し、DoS攻撃のリスクを軽減
- ファイル名から危険な特殊文字を除去(preg_replace使用)
- 追加のセキュリティヘッダー(X-Content-Type-Options、X-Frame-Options)を実装
- より厳密な文字コード変換(変換できない文字は’?’に置換)
- CSRF対策の実装
<?php
/**
* Shift-JIS CSV変換・ダウンロードスクリプト
* UTF-8のテキストデータをShift-JIS形式のCSVファイルとしてダウンロードする
*
* セキュリティ対策:
* - CSRF対策
* - XSS対策
* - セッションセキュリティ
* - 入力検証
* - レート制限
* - メモリ使用制限
*/
// エラー設定
error_reporting(0);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', 'error.log');
// セッションセキュリティ設定
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_samesite', 'Strict');
ini_set('session.gc_maxlifetime', 3600);
session_start();
// CSRFトークンの生成
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// nonce生成(CSP用)
$nonce = base64_encode(random_bytes(16));
// POSTリクエストの処理
if ($_SERVER["REQUEST_METHOD"] == "POST") {
try {
// レート制限チェック
if (isset($_SESSION['last_request_time'])) {
if (time() - $_SESSION['last_request_time'] < 1) {
throw new Exception('リクエストが多すぎます。しばらく待ってから再度お試しください。');
}
}
$_SESSION['last_request_time'] = time();
// CSRF対策
if (!isset($_SESSION['csrf_token']) ||
!isset($_POST['csrf_token']) ||
!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
throw new Exception('不正なリクエストです。ページを更新して再度お試しください。');
}
// 入力バリデーション
$input_text = filter_input(INPUT_POST, 'input_text', FILTER_DEFAULT);
if ($input_text === null || $input_text === false || trim($input_text) === '') {
throw new Exception('入力が無効です。テキストを入力してください。');
}
$input_text = htmlspecialchars($input_text, ENT_QUOTES, 'UTF-8');
// メモリとサイズの制限チェック
if (strlen($input_text) > 1000000 || memory_get_usage() > 8388608) {
throw new Exception('入力が大きすぎます。1MB以下のテキストを入力してください。');
}
// UTF-8からShift-JISへの変換
$shift_jis_text = mb_convert_encoding($input_text, 'SJIS', 'UTF-8', '?');
if ($shift_jis_text === false) {
throw new Exception('文字コードの変換に失敗しました。');
}
// 安全なファイル名の生成
$filename = basename(date('Ymd_His') . '_export.csv');
$safe_filename = preg_replace('/[^\x20-\x7E]/', '', $filename);
// レスポンスヘッダーの設定
header_remove();
header('Content-Type: text/csv; charset=Shift_JIS');
header('Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode($safe_filename));
header('Content-Length: ' . strlen($shift_jis_text));
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header("Content-Security-Policy: default-src 'none'; script-src 'nonce-{$nonce}' https://pagead2.googlesyndication.com; style-src 'self' 'unsafe-inline'; frame-src https://googleads.g.doubleclick.net");
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
header('Permissions-Policy: geolocation=(), microphone=(), camera=()');
header('Referrer-Policy: strict-origin-when-cross-origin');
header('Cache-Control: private, no-cache, no-store, must-revalidate');
echo $shift_jis_text;
exit;
} catch (Exception $e) {
$error_message = $e->getMessage();
}
}
?>
こちらもどうぞ。


![[PHP]ウェブページの内容を抽出するオンラインツールを作るには?](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMjAiIGhlaWdodD0iMTk4IiB2aWV3Qm94PSIwIDAgMzIwIDE5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2ZmZmZmZiIvPjwvc3ZnPg==)
![[Mac] PC内で検証用ウェブサーバを動かす【php -S】](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMjAiIGhlaWdodD0iMTk4IiB2aWV3Qm94PSIwIDAgMzIwIDE5OCI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2ZmZmZmZiIvPjwvc3ZnPg==)

らくらくスマートフォンで半角カナを入力する 【文字コードの基本】
銀行口座の名義人など、正確な入力が必要な場合は全角カナと半角カナを適切に区別する必要があります。らくらくスマートフォンで半角カナを入力するには、まずひらがなで入力し、「変換」ボタンを押します。すると、変換候補の中に半角カナの文字列もあります。全角カナと半角カナの違いスマートフォンで入力していると、うまくいかないことがあります。例えば、先日あったのが、電気や通信の切替えキャンペーンのキャッシュバックの振込先。「日本語入力ならでは」なのですが、カタカナ(あと数字・英字も)には全角...

『螳牙・讀懃エ「を検索』 検索バーでの文字化け 【McAfeeウェブアドバイザーの設定】
アドレスバーで検索しようとしたら、変な文字化けが出てきたよーアドレスバーに「mcafee」と続けて検索すると、文字化けが見られるかもしれません。McAfeeのセキュリティソフトを利用している場合に起こります。ポイント『螳牙・讀懃エ「』は、「安全検索」が文字化けしたもの。McAfeeのセキュリティソフトがインストールされた時に、古い文字コードでブラウザが設定されていた。「安全検索」なのに、なぜか不安な文字列が出てくる、というお話でした。「McAfee」について検索していたらパソ...
![[PHP]ウェブページの内容を抽出するオンラインツールを作るには?](https://chiilabo.com/wp-content/uploads/2024/08/image-9-20240814-121740-320x198.jpg)
[PHP]ウェブページの内容を抽出するオンラインツールを作るには?
ウェブページから必要な記事を簡単に抽出するツールを作りました。使い方は、URLを入力して「Extract Article」ボタンを押すだけで、記事内容が表示されます。信頼できるソースのURLのみを使用し、個人利用や研究目的に限定してください。ツールの使い方インターネット上には膨大な情報があふれていて、必要な情報だけを見るのは大変な作業です。そこで、ウェブページから記事を簡単に抽出できるツールを作りました。(ツール)ツールの使い方を具体的に説明しましょう。まず、ウェブブラウザで...
![[Mac] PC内で検証用ウェブサーバを動かす【php -S】](https://chiilabo.com/wp-content/uploads/2023/06/image-4-3-320x198.jpg)
[Mac] PC内で検証用ウェブサーバを動かす【php -S】
phina.js のプログラムをローカルで検証するために、ウェブサーバを立ち上げることにしました。ブラウザでHTMLファイルを開いてもサイトと違うただのファイルとして html を開いた場合(たとえば「file:///Users/user/html/index.html」など)、JavaScriptから相対アドレスでほかのローカルファイルを読み込んだりはできません。JavaScriptのセキュリティ上の制限で、ローカルファイルにはアクセスできないからです。そのため、サイトデー...
QRコードを読み込むと、関連記事を確認できます。
