140

文字列をサニタイズしてファイル名に使用できるようにするphp関数を探しています。便利なものを知っている人はいますか?

(書けるけど、キャラの見落としが心配!)

編集: Windows NTFS ファイルシステムにファイルを保存する場合。

4

18 に答える 18

175

Dominic Rodger が気づいた問題を修正するために、Tor Valamo のソリューションを少し調整すると、以下を使用できます。

// Remove anything which isn't a word, whitespace, number
// or any of the following caracters -_~,;[]().
// If you don't need to handle multi-byte characters
// you can use preg_replace rather than mb_ereg_replace
// Thanks @Łukasz Rysiak!
$file = mb_ereg_replace("([^\w\s\d\-_~,;\[\]\(\).])", '', $file);
// Remove any runs of periods (thanks falstro!)
$file = mb_ereg_replace("([\.]{2,})", '', $file);
于 2010-01-07T16:10:23.880 に答える
43

rawurlencode() の使用はどうですか? http://www.php.net/manual/en/function.rawurlencode.php

中国語の文字もサニタイズする関数は次のとおりです。

public static function normalizeString ($str = '')
{
    $str = strip_tags($str); 
    $str = preg_replace('/[\r\n\t ]+/', ' ', $str);
    $str = preg_replace('/[\"\*\/\:\<\>\?\'\|]+/', ' ', $str);
    $str = strtolower($str);
    $str = html_entity_decode( $str, ENT_QUOTES, "utf-8" );
    $str = htmlentities($str, ENT_QUOTES, "utf-8");
    $str = preg_replace("/(&)([a-z])([a-z]+;)/i", '$2', $str);
    $str = str_replace(' ', '-', $str);
    $str = rawurlencode($str);
    $str = str_replace('%', '-', $str);
    return $str;
}

ここに説明があります

  1. HTML タグを取り除く
  2. 改行/タブ/改行を削除
  3. フォルダとファイル名の不正な文字を削除
  4. 文字列を小文字にする
  5. Éàû などの外国語のアクセントを html エンティティに変換して削除し、コードを削除して文字を保持します。
  6. スペースをダッシュ​​に置き換える
  7. 前の手順を通過し、サーバー上で競合するファイル名に入る可能性のある特殊文字をエンコードします。元。「中文百强网」
  8. 「%」をダッシュ​​に置き換えて、ファイルのクエリ時にファイルのリンクがブラウザによって書き換えられないようにします。

OK、一部のファイル名は関連性がありませんが、ほとんどの場合は機能します。

元。元の名前: "საბეჭდი-და-ტიპოგრაფიული.jpg"

出力名: "-E1-83-A1-E1-83-90-E1-83-91-E1-83-94-E1-83-AD-E1-83-93-E1-83-98--E1- 83-93-E1-83-90--E1-83-A2-E1-83-98-E1-83-9E-E1-83-9D-E1-83-92-E1-83-A0-E1-83 -90-E1-83-A4-E1-83-98-E1-83-A3-E1-83-9A-E1-83-98.jpg"

404 エラーよりもそのほうがよいでしょう。

お役に立てば幸いです。

カール。

于 2013-09-26T03:17:37.130 に答える
40

文字を見落とすことを心配する代わりに、喜んで使用できる文字のホワイトリストを使用してみませんか?たとえば、ちょうど良いol'、、、およびa-zピリオド()の単一のインスタンスを許可できます。これは明らかにほとんどのファイルシステムよりも制限がありますが、安全を確保する必要があります。0-9_.

于 2010-01-07T16:02:45.280 に答える
19

さて、tempnam()はあなたのためにそれをします。

http://us2.php.net/manual/en/function.tempnam.php

しかし、それはまったく新しい名前を作成します。

既存の文字列をサニタイズするには、ユーザーが入力できるものを制限し、文字、数字、ピリオド、ハイフン、アンダースコアにしてから、単純な正規表現でサニタイズします。エスケープする必要のある文字を確認してください。そうしないと、誤検知が発生する可能性があります。

$sanitized = preg_replace('/[^a-zA-Z0-9\-\._]/','', $filename);
于 2010-01-07T16:04:25.013 に答える
14
preg_replace("[^\w\s\d\.\-_~,;:\[\]\(\]]", '', $file)

システムで許可されている文字に応じて、有効な文字をさらに追加/削除します。

または、ファイルの作成を試みて、問題がある場合はエラーを返すこともできます。

于 2010-01-07T16:02:08.577 に答える
6

次の式は、きれいで使いやすい文字列を作成します。

/[^a-z0-9\._-]+/gi

今日の財務: 請求今日の財務請求に変える

于 2010-01-07T16:01:15.690 に答える
2

これらは少し重いかもしれませんが、どんな文字列でも「安全な」enスタイルのファイル名またはフォルダー名にサニタイズするのに十分な柔軟性があります (または、それを曲げると、ナメクジやものをスクラブすることさえできます)。

1) 完全なファイル名の作成 (入力が完全に切り捨てられた場合のフォールバック名付き):

str_file($raw_string, $word_separator, $file_extension, $fallback_name, $length);

2) または、完全なファイル名を作成せずにフィルター util のみを使用する (strict モードtrueでは、ファイル名に [] または () を使用できません):

str_file_filter($string, $separator, $strict, $length);

3) これらの関数は次のとおりです。

// Returns filesystem-safe string after cleaning, filtering, and trimming input
function str_file_filter(
    $str,
    $sep = '_',
    $strict = false,
    $trim = 248) {

    $str = strip_tags(htmlspecialchars_decode(strtolower($str))); // lowercase -> decode -> strip tags
    $str = str_replace("%20", ' ', $str); // convert rogue %20s into spaces
    $str = preg_replace("/%[a-z0-9]{1,2}/i", '', $str); // remove hexy things
    $str = str_replace("&nbsp;", ' ', $str); // convert all nbsp into space
    $str = preg_replace("/&#?[a-z0-9]{2,8};/i", '', $str); // remove the other non-tag things
    $str = preg_replace("/\s+/", $sep, $str); // filter multiple spaces
    $str = preg_replace("/\.+/", '.', $str); // filter multiple periods
    $str = preg_replace("/^\.+/", '', $str); // trim leading period

    if ($strict) {
        $str = preg_replace("/([^\w\d\\" . $sep . ".])/", '', $str); // only allow words and digits
    } else {
        $str = preg_replace("/([^\w\d\\" . $sep . "\[\]\(\).])/", '', $str); // allow words, digits, [], and ()
    }

    $str = preg_replace("/\\" . $sep . "+/", $sep, $str); // filter multiple separators
    $str = substr($str, 0, $trim); // trim filename to desired length, note 255 char limit on windows

    return $str;
}


// Returns full file name including fallback and extension
function str_file(
    $str,
    $sep = '_',
    $ext = '',
    $default = '',
    $trim = 248) {

    // Run $str and/or $ext through filters to clean up strings
    $str = str_file_filter($str, $sep);
    $ext = '.' . str_file_filter($ext, '', true);

    // Default file name in case all chars are trimmed from $str, then ensure there is an id at tail
    if (empty($str) && empty($default)) {
        $str = 'no_name__' . date('Y-m-d_H-m_A') . '__' . uniqid();
    } elseif (empty($str)) {
        $str = $default;
    }

    // Return completed string
    if (!empty($ext)) {
        return $str . $ext;
    } else {
        return $str;
    }
}

したがって、ユーザー入力が次のようになっているとしましょう。.....&lt;div&gt;&lt;/div&gt;<script></script>&amp; Weiß Göbel 中文百强网File name %20 %20 %21 %2C Décor \/. /. . z \... y \...... x ./ “This name” is & 462^^ not &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = that grrrreat -][09]()1234747) საბეჭდი-და-ტიპოგრაფიული

そして、それをより使いやすいものに変換して、ファイル名の長さが 255 文字の tar.gz を作成します。以下は使用例です。注: この例には、コンセプトの証明として不正な形式の tar.gz 拡張子が含まれています。ホワイトリストに対して文字列が作成された後、引き続き ext をフィルタリングする必要があります。

$raw_str = '.....&lt;div&gt;&lt;/div&gt;<script></script>&amp; Weiß Göbel 中文百强网File name  %20   %20 %21 %2C Décor  \/.  /. .  z \... y \...... x ./  “This name” is & 462^^ not &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = that grrrreat -][09]()1234747) საბეჭდი-და-ტიპოგრაფიული';
$fallback_str = 'generated_' . date('Y-m-d_H-m_A');
$bad_extension = '....t&+++a()r.gz[]';

echo str_file($raw_str, '_', $bad_extension, $fallback_str);

出力は次のようになります。_wei_gbel_file_name_dcor_._._._z_._y_._x_._this_name_is_462_not_that_grrrreat_][09]()1234747)_.tar.gz

ここで遊ぶことができます: https://3v4l.org/iSgi8

または Gist: https://gist.github.com/dhaupin/b109d3a8464239b7754a

編集:スペースの代わりに 更新されたスクリプト フィルター&nbsp;、更新された 3v4l リンク

于 2016-01-20T19:23:21.063 に答える
1

現在私が知っている中で最も優れているのは、Nette フレームワークの静的メソッドStrings::webalizeです。

ところで、これはすべての分音記号を基本記号に変換します.. š=>s ü=>u ß=>ss など.

ファイル名には、ドット「.」を追加する必要があります。許可された文字パラメーターに。

/**
 * Converts to ASCII.
 * @param  string  UTF-8 encoding
 * @return string  ASCII
 */
public static function toAscii($s)
{
    static $transliterator = NULL;
    if ($transliterator === NULL && class_exists('Transliterator', FALSE)) {
        $transliterator = \Transliterator::create('Any-Latin; Latin-ASCII');
    }

    $s = preg_replace('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{2FF}\x{370}-\x{10FFFF}]#u', '', $s);
    $s = strtr($s, '`\'"^~?', "\x01\x02\x03\x04\x05\x06");
    $s = str_replace(
        array("\xE2\x80\x9E", "\xE2\x80\x9C", "\xE2\x80\x9D", "\xE2\x80\x9A", "\xE2\x80\x98", "\xE2\x80\x99", "\xC2\xB0"),
        array("\x03", "\x03", "\x03", "\x02", "\x02", "\x02", "\x04"), $s
    );
    if ($transliterator !== NULL) {
        $s = $transliterator->transliterate($s);
    }
    if (ICONV_IMPL === 'glibc') {
        $s = str_replace(
            array("\xC2\xBB", "\xC2\xAB", "\xE2\x80\xA6", "\xE2\x84\xA2", "\xC2\xA9", "\xC2\xAE"),
            array('>>', '<<', '...', 'TM', '(c)', '(R)'), $s
        );
        $s = @iconv('UTF-8', 'WINDOWS-1250//TRANSLIT//IGNORE', $s); // intentionally @
        $s = strtr($s, "\xa5\xa3\xbc\x8c\xa7\x8a\xaa\x8d\x8f\x8e\xaf\xb9\xb3\xbe\x9c\x9a\xba\x9d\x9f\x9e"
            . "\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3"
            . "\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
            . "\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xfe"
            . "\x96\xa0\x8b\x97\x9b\xa6\xad\xb7",
            'ALLSSSSTZZZallssstzzzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTsraaaalccceeeeiiddnnooooruuuuyt- <->|-.');
        $s = preg_replace('#[^\x00-\x7F]++#', '', $s);
    } else {
        $s = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); // intentionally @
    }
    $s = str_replace(array('`', "'", '"', '^', '~', '?'), '', $s);
    return strtr($s, "\x01\x02\x03\x04\x05\x06", '`\'"^~?');
}


/**
 * Converts to web safe characters [a-z0-9-] text.
 * @param  string  UTF-8 encoding
 * @param  string  allowed characters
 * @param  bool
 * @return string
 */
public static function webalize($s, $charlist = NULL, $lower = TRUE)
{
    $s = self::toAscii($s);
    if ($lower) {
        $s = strtolower($s);
    }
    $s = preg_replace('#[^a-z0-9' . preg_quote($charlist, '#') . ']+#i', '-', $s);
    $s = trim($s, '-');
    return $s;
}
于 2016-09-14T05:52:41.910 に答える
1

これはすべて、サーバーへのハッキング (またはその他の損害) に使用できるファイル名を作成できるかどうかという問題にかかっているようです。そうでない場合、単純な答えは、最終的に使用される場所ならどこでもファイルを作成することです (それが選択されるオペレーティングシステムになるため、間違いありません)。オペレーティングシステムにそれを整理させてください。苦情がある場合は、その苦情を検証エラーとしてユーザーに戻します。

ファイル名がそのOSに対して適切に形成されていない場合、すべての(私はかなり確信している)オペレーティングシステムが文句を言うので、これには確実に移植できるという追加の利点があります。

ファイル名で悪意のあることを行うことできる場合、常駐オペレーティング システムでファイル名をテストする前に適用できる対策がある可能性があります。これは、ファイル名の完全な「サニテーション」よりも複雑ではありません。

于 2017-10-27T17:01:32.287 に答える
0

/また..、ユーザーが指定したファイル名は有害である可能性があります。したがって、次のような方法でこれらを取り除く必要があります。

$fname = str_replace('..', '', $fname);
$fname = str_replace('/',  '', $fname);
于 2010-01-07T16:04:56.493 に答える
0

一方通行

$bad='/[\/:*?"<>|]/';
$string = 'fi?le*';

function sanitize($str,$pat)
{
    return preg_replace($pat,"",$str);

}
echo sanitize($string,$bad);
于 2010-01-08T00:56:09.117 に答える
-4

$fname = str_replace('/','',$fname);

ユーザーは 2 つの単語を区切るためにスラッシュを使用する可能性があるため、NULL ではなくダッシュに置き換えることをお勧めします。

于 2013-04-04T22:02:04.077 に答える