この関数を PHP で記述しようとしないでください。必然的に間違いを犯し、アプリケーションは必然的に任意のリモート実行エクスプロイトを持ちます。
まず、実際にどのような問題を解決しているのかを考えてみましょう。PHPからPythonにデータを取得しようとしているだけだと思います。.py ファイルではなく .ini ファイルを書き込もうとするかもしれません。Python には、優れた ini 構文パーサーConfigParserがあります。PHP で、明らかに間違っている可能性のある引用関数を作成することができます。
XML ファイルを作成することもできます。PHP と Python 用の XML パーサーとエミッターは多すぎて、ここにリストすることさえできません。
これがひどい、ひどい考えだと本当に納得できない場合は、少なくともPythonがそのようなことを行うために持っている既存の関数を使用できます。repr()
これを行うために Python スクリプトを実行する便利な PHP 関数を次に示します。
<?php
function py_escape($input) {
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w")
);
$process = proc_open(
"python -c 'import sys; sys.stdout.write(repr(sys.stdin.read()))'",
$descriptorspec, $pipes);
fwrite($pipes[0], $input);
fclose($pipes[0]);
$chunk_size = 8192;
$escaped = fread($pipes[1], $chunk_size);
if (strlen($escaped) == $chunk_size) {
// This is important for security.
die("That string's too big.\n");
}
proc_close($process);
return $escaped;
}
// Example usage:
$x = "string \rfull \nof\t crappy stuff";
print py_escape($x);
このチェックは、入力がそれぞれとchunk_size
のように見える 2 つの非常に長い文字列になるという攻撃を防ぐことを目的としています。さて、Python は一重引用符で囲まれた文字列を行の途中で終了させないため、その素朴な攻撃は正確には機能しません。継続 ("\") を適切な場所に挿入し、次のようなものを使用すると、実行されるコードを挿入できます。("hello " + ("." * chunk_size))
'; os.system("do bad stuff")
system()
os.system(map(chr, ...))
Python ソース ファイルの行の長さにも制限があるため、読み取りと蓄積を続けるのではなく、単純に 1 つのチャンクを読み取り、さらに出力があればあきらめることを選択しました。私が知っている限りでは、それは別の攻撃ベクトルである可能性があります. Python は、システム上で任意のソース コードを作成する任意の人物に対して安全であることを意図していないため、この領域が監査される可能性は低いです。
この些細な例のためにこれをすべて考えなければならなかったという事実は、データ交換フォーマットとして Python ソース コードを使用してはならない理由のもう 1 つの例にすぎません。