Skip to content

mimikero

Program / Security etc…

Menu
Menu

PHPのProcessで日本語パラメータを扱うとsurrogates not allowed となる

Posted on 2024年11月30日2024年11月30日 by mimi

背景

エックスサーバーで PHPからPythonスクリプトを呼び出す際に、日本語パラメータを渡すとPythonでUnicodeEncodeErrorが発生していた。

$parameters = ['あ'];
$command = array_merge(['python3', $filePath], $parameters);
$process = new Process($command);
$process->run();

Python

encoded = sys.argv[1].encode('utf-8')
print(encoded)

実行後

UnicodeEncodeError: 'utf-8' codec can't encode characters in position 0-2: surrogates not allowed

エラーを無視してエンコード

encoded = sys.argv[1].encode('utf-8', errors='surrogatepass')
print(encoded)
print("あ".encode('utf-8'))
b'\xed\xb3\xa3\xed\xb2\x81\xed\xb2\x82'
b'\xe3\x81\x82'

同じ文字列なのに結果が違っている。
昔のPythonでは日本語でトラブルが度々あったが、最近では見ない。
ChatGPTやsurrogatepass エラーで調べてもあまり出てこない。うーむ。


原因

Pythonでは、コマンドライン引数や標準入力のデコードに使用するエンコーディングがシステムロケール(LANG環境変数)によって決定されます。

1. ロケールの影響

LANG環境変数が未設定、または不適切に設定されている場合、Pythonは標準エンコーディングをasciiまたはCロケールとして扱う。
日本語を含む非ASCII文字は、この設定ではサポートされず、エンコードエラーやサロゲートペアに関する問題が発生するらしい。

2. Symfony Processによる環境引き継ぎ

PHPのProcessクラスを用いてPythonスクリプトを呼び出す際、環境変数が正しく継承されない場合があります。
このため、PHP側で適切なロケールを明示的に設定しないと、Python実行環境が正しいエンコーディングを使用しないらしい。

3. サロゲートペアの問題

errors='surrogatepass'を指定すると、UTF-16で使用されるサロゲートペアがUTF-8エンコードに影響を及ぼします。
UTF-8において通常無効とされるコードポイントを許可してしまうため、異常なバイト列が生成されてしまうのだとか。

確認

ロケール・エンコーディングをPythonから確認

(PHPのProcessから実行)
import locale
print(locale.getpreferredencoding()) # 使用されているエンコーディングを確認
ANSI_X3.4-1968

ならば環境変数を入れよう

Symfony Processを用いる際に、LANG環境変数を明示的に設定します。

$process = new Process($command);
$process->setEnv(['LANG' => 'en_US.UTF-8']);
$process->run();

正しいロケールで動作しているかを確認

import locale
print(locale.getpreferredencoding()) # 使用されているエンコーディングを確認
UTF-8

問題なさそうなので、入力してみる

encoded = sys.argv[1].encode('utf-8')
print(encoded)
print("あ".encode('utf-8'))
b'\xe3\x81\x82'
b'\xe3\x81\x82'

問題なくUTF-8で入力されている。

(おまけ)Pythonファイルで指定してみる

Pythonスクリプト内でロケールを強制的に設定する方法はダメだった。

import os
import locale

# LANG環境変数を明示的に設定
os.environ['LANG'] = 'en_US.UTF-8'
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')


encoded = sys.argv[1].encode('utf-8', errors='surrogatepass')
print(encoded)


UTF-8
b'\xed\xb3\xa3\xed\xb2\x81\xed\xb2\x82'

ロケール設定はUTF-8となるが、入力処理で躓いている。

ads

trends post

Spring Boot と Spring Framework バージョン 対応表まとめ(SpringBoot v2,v3)

Excelデータのスクロールバーが短い現象を保存を使わずに直す

エックスサーバーにLaravelプロジェクトをデプロイ

latest post

  • Cockpit-Docker をubuntu20にインストールする
  • PHPのProcessで日本語パラメータを扱うとsurrogates not allowed となる
  • XServerでexecやshell_execを実行すると、Unable to forkとエラーが出るとき
  • tenable解説 混合リソースの検出
  • tenable解説 WebDAV
  • tenable解説 ディレクトリリスト
  • tenable解説 暗号化されていないパスワードフォーム
  • tenable解説 オートコンプリートのパスワードフィールド
  • tenable解説 CVS/SVN ユーザーの漏洩
  • tenable解説 プライベート IP アドレスの漏洩
  • tenable解説 メールアドレスの漏洩
  • tenable解説 バックアップファイル
  • tenable解説 バックアップディレクトリ
  • tenable解説 共通ファイルの検出
  • tenable解説 共通ディレクトリの検出

カテゴリー

  • Authentication & Session
  • BurpSuite
  • Component Vulnerability
  • Data Exposure
  • HTTP Security Header
  • Lodash
  • Moment.js
  • tenable
  • Web Applications
  • Web Servers
  • 未分類
  • 脆弱性解説
©2025 mimikero | WordPress Theme by Superbthemes.com