dosya adı için dize temizleyici


113

Bir dizgeyi sterilize edecek ve onu bir dosya adı için kullanıma hazır hale getirecek bir php işlevi arıyorum. Kullanışlı bir tane bilen var mı?

(Bir tane yazabilirim ama bir karakteri gözden kaçıracağımdan endişeliyim!)

Düzenle: dosyaları bir Windows NTFS dosya sistemine kaydetmek için.


1
Daha spesifik olabilir misiniz: Umlaut'lara ne olacak (ana karaktere dönüştürme veya çıkarma?) Özel karakterlere ne olacak?
Pekka

Hangi Dosya Sistemi için? Onlar farklı. Bkz. En.wikipedia.org/wiki/…
Gordon

Windows :) 15 karaktere ihtiyacınız var.
user151841

1
Olası her istenmeyen karakteri kontrol etmek mümkün olmadığından bazı yanıtlarda önerilen "kara liste" çözümlerinin yeterli olmadığını belirtmek isterim (özel karakterlere ek olarak, aksanlı ve çift noktalı karakterler vardır, tümü ingilizce olmayan / latin alfabeler, kontrol karakterleri vb. Bu nedenle, "beyaz liste" yaklaşımının her zaman daha iyi olduğunu ve dizeyi normalleştirmenin (Blair McMillan'ın Dominic Rodger'ın cevabı hakkındaki yorumunda önerildiği gibi) aksanlı, umlautlu vb. Harflerin doğal olarak işlenmesine izin vereceğini iddia ediyorum
Sean the Bean

Normal ifadeler kullanmanın iyi bir yolu olabilir, yaptığım şu python betiğine bakın: github.com/gsscoder/normalize-fn
gsscoder

Yanıtlar:


42

Karakterleri gözden kaçırmaktan endişelenmek yerine - kullanmaktan mutlu olduğunuz karakterlerin beyaz listesini kullanmaya ne dersiniz? Örneğin, 'sadece iyi ol izin verebilir a-z, 0-9, _ve bir dönemin tek örneği ( .). Bu, çoğu dosya sisteminden daha sınırlayıcıdır, ancak sizi güvende tutmalıdır.


40
Umlaut'lu diller için iyi değil. Bu, Québec için Qubec, Düsseldorf için Dsseldorf vb. İle sonuçlanır.
Pekka

15
Doğru - ama dediğim gibi: "Örneğin".
Dominic Rodger

5
OP için tamamen kabul edilebilir olabilir. Aksi takdirde, php.net/manual/en/class.normalizer.php
Blair McMillan

3
Aslında sorulan bu değildi. Operasyon, dizeyi sterilize etmek için bir işlev ister, alternatif değil.
i.am.michiel

3
@ i.am.michiel, belki, ancak OP'nin kabul ettiği göz önüne alındığında, yararlı bulduklarını varsayacağım.
Dominic Rodger

157

Dominic Rodger tarafından fark sorunu çözmek için Tor Valamo en çözümüne ufak bir değişiklikle, yapma, sen verebilir kullanın:

// 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);

43
Normal ifade bağımlılarına bayılırım! -_ ~
AVProgrammer

2
@ iim.hlk - evet, sarma parantezi eksikti. Şimdi ekledim. Teşekkürler!
Sean Vieira

2
orada bir kusur var, onu ikiye ayırmalı ve ..daha sonra kontrolü yapmalısınız . Örneğin .?., varolmakla sonuçlanır ... Filtrelediğinizden beri /, şimdi bundan nasıl daha fazla yararlanacağınızı göremiyorum, ancak buradaki kontrolün neden ..etkisiz olduğunu gösteriyor . Daha da iyisi, muhtemelen değiştirmeyin, uygun değilse reddedin.
falstro

2
Çünkü bu değerlerden hiçbiri Windows dosya sisteminde yasa dışı değildir ve neden gerekenden daha fazla bilgi kaybedersiniz? [^a-z0-9_-]Gerçekten kısıtlayıcı olmak istiyorsanız normal ifadeyi basitçe değiştirebilirsiniz - ya da sadece oluşturulmuş bir ad kullanın ve verilen adı atıp tüm bu sorunları önleyin . :-)
Sean Vieira

3
Unutmayın: yasa dışıdır.
JasonXA

50

İstendiği gibi bir dosya sistemini bu şekilde sterilize edebilirsiniz.

function filter_filename($name) {
    // remove illegal file system characters https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
    $name = str_replace(array_merge(
        array_map('chr', range(0, 31)),
        array('<', '>', ':', '"', '/', '\\', '|', '?', '*')
    ), '', $name);
    // maximise filename length to 255 bytes http://serverfault.com/a/9548/44086
    $ext = pathinfo($name, PATHINFO_EXTENSION);
    $name= mb_strcut(pathinfo($name, PATHINFO_FILENAME), 0, 255 - ($ext ? strlen($ext) + 1 : 0), mb_detect_encoding($name)) . ($ext ? '.' . $ext : '');
    return $name;
}

Dosya sisteminde diğer her şeye izin verilir, bu nedenle soru mükemmel bir şekilde yanıtlanır ...

... ancak daha sonra güvenli olmayan bir HTML bağlamında kullanırsanız , örneğin bir dosya adında tek tırnak işaretlerine izin vermek tehlikeli olabilir' çünkü bu kesinlikle yasal dosya adı:

 ' onerror= 'alert(document.cookie).jpg

bir XSS deliği haline gelir :

<img src='<? echo $image ?>' />
// output:
<img src=' ' onerror= 'alert(document.cookie)' />

Bu nedenle, popüler CMS yazılımı Wordpress bunları kaldırır, ancak tüm ilgili karakterleri yalnızca bazı güncellemelerden sonra kapladılar :

$special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", "%", "+", chr(0));
// ... a few rows later are whitespaces removed as well ...
preg_replace( '/[\r\n\t -]+/', '-', $filename )

Son olarak, listeleri artık URI yeniden ayrılmış karakterler ve URL güvenli olmayan karakterler listesinin parçası olan karakterlerin çoğunu içermektedir .

Elbette tüm bu karakterleri HTML çıktısına kodlayabilirsiniz, ancak çoğu geliştirici ve ben de "Üzgünüm olmaktan iyidir" deyimini takip edin ve bunları önceden silin.

Sonunda şunu kullanmanızı öneririm:

function filter_filename($filename, $beautify=true) {
    // sanitize filename
    $filename = preg_replace(
        '~
        [<>:"/\\|?*]|            # file system reserved https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
        [\x00-\x1F]|             # control characters http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
        [\x7F\xA0\xAD]|          # non-printing characters DEL, NO-BREAK SPACE, SOFT HYPHEN
        [#\[\]@!$&\'()+,;=]|     # URI reserved https://tools.ietf.org/html/rfc3986#section-2.2
        [{}^\~`]                 # URL unsafe characters https://www.ietf.org/rfc/rfc1738.txt
        ~x',
        '-', $filename);
    // avoids ".", ".." or ".hiddenFiles"
    $filename = ltrim($filename, '.-');
    // optional beautification
    if ($beautify) $filename = beautify_filename($filename);
    // maximize filename length to 255 bytes http://serverfault.com/a/9548/44086
    $ext = pathinfo($filename, PATHINFO_EXTENSION);
    $filename = mb_strcut(pathinfo($filename, PATHINFO_FILENAME), 0, 255 - ($ext ? strlen($ext) + 1 : 0), mb_detect_encoding($filename)) . ($ext ? '.' . $ext : '');
    return $filename;
}

Dosya sistemiyle ilgili sorunlara neden olmayan diğer her şey ek bir işlevin parçası olmalıdır:

function beautify_filename($filename) {
    // reduce consecutive characters
    $filename = preg_replace(array(
        // "file   name.zip" becomes "file-name.zip"
        '/ +/',
        // "file___name.zip" becomes "file-name.zip"
        '/_+/',
        // "file---name.zip" becomes "file-name.zip"
        '/-+/'
    ), '-', $filename);
    $filename = preg_replace(array(
        // "file--.--.-.--name.zip" becomes "file.name.zip"
        '/-*\.-*/',
        // "file...name..zip" becomes "file.name.zip"
        '/\.{2,}/'
    ), '.', $filename);
    // lowercase for windows/unix interoperability http://support.microsoft.com/kb/100625
    $filename = mb_strtolower($filename, mb_detect_encoding($filename));
    // ".file-name.-" becomes "file-name"
    $filename = trim($filename, '.-');
    return $filename;
}

Ve bu noktada, sonuç boşsa bir dosya adı oluşturmanız gerekir ve UTF-8 karakterlerini kodlamak isteyip istemediğinize karar verebilirsiniz. Ancak, web barındırma bağlamlarında kullanılan tüm dosya sistemlerinde UTF-8'e izin verildiğinden buna ihtiyacınız yoktur.

Yapmanız gereken tek şey, kullanmaktır urlencode()(umarız tüm URL'lerinizle yaptığınız gibi), böylece dosya adı საბეჭდი_მანქანა.jpgsizin <img src>veya şu URL olarak olur <a href>: http://www.maxrev.de/html/img/%E1%83% A1% E1% 83% 90% E1% 83% 91% E1% 83% 94% E1% 83% AD% E1% 83% 93% E1% 83% 98_% E1% 83% 9B% E1% 83% 90% E1% 83% 9C% E1% 83% A5% E1% 83% 90% E1% 83% 9C% E1% 83% 90.jpg

Stackoverflow bunu yapar, böylece bu bağlantıyı bir kullanıcının yapacağı şekilde gönderebilirim :
http://www.maxrev.de/html/img/ საბეჭდი_მანქანა. Jpg

Yani bu tam bir yasal dosya adıdır ve @ SequenceDigitale.com'un cevabında belirtildiği gibi bir sorun değildir .


3
Aferin. Benim için en yararlı cevap. +1

Oh ... Fonksiyon iyi çalışıyor, ama bir süredir - her karakterin arasına - r-u-l-e-sbunun neden olduğuna dair hiçbir fikrim yok. Elbette, bu işlevin hatası değil, sadece sormak - bu tür davranışların nedeni ne olabilir? Yanlış kodlama mı?

1
Oh iyi ... Sadece bir hata ayıklama yapılmış ve sadece sonra olur preg_replacein filter_filename().

Bu yorumları kaldırdıktan sonra tekrar çalışmaya başladı.

Hangi yorumları kaldırdınız? Daha kolaysa
mgutt

43

Rawurlencode () kullanmaya ne dersiniz? http://www.php.net/manual/en/function.rawurlencode.php

İşte Çince Karakterleri bile sterilize eden bir işlev:

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;
}

İşte açıklama

  1. HTML Etiketlerini Çıkar
  2. Koparma / Sekmeleri / İade Taşıyıcısını Çıkarın
  3. Klasör ve dosya adı için Yasadışı Karakterleri Kaldır
  4. Dizeyi küçük harfle yazın
  5. Éàû gibi yabancı aksanları html varlıklarına dönüştürerek kaldırın ve ardından kodu kaldırıp harfi saklayın.
  6. Boşlukları kısa çizgilerle değiştirin
  7. Önceki adımları geçebilecek özel karakterleri kodlayın ve sunucuda çakışma dosya adını girin. ör. "中文 百强 网"
  8. Dosyayı sorgularken dosyanın bağlantısının tarayıcı tarafından yeniden yazılmayacağından emin olmak için "%" kısmını çizgilerle değiştirin.

Tamam, bazı dosya adları uygun olmayacak ama çoğu durumda işe yarayacak.

ör. Orijinal Ad: "საბეჭდი-და-ტიპოგრაფიული. Jpg"

Çıkış Adı: "-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 hatasından daha iyi.

Umarım yardımcı olmuştur.

Carl.


1
NULL ve Control karakterlerini kaldırmıyorsunuz. 0'dan 32'ye ASCII'nin tümü dizeden kaldırılmalıdır.
Basil Musa

UTF-8'e dosya sisteminde izin verilir ve URL'lerde buna izin verilir, öyleyse neden 404 hatası üretsin? Yapmanız gereken tek şey URL'yi şifrelemektir http://www.maxrev.de/html/img/საბეჭდი_მანქანა.jpgiçin http://www.maxrev.de/html/img/%E1%83%A1%E1%83%90%E1%83%91%E1%83%94%E1%83%AD%E1%83%93%E1%83%98_%E1%83%9B%E1%83%90%E1%83%9C%E1%83%A5%E1%83%90%E1%83%9C%E1%83%90.jpgumarım tüm URL'ler ile yaptığımız gibi HTML kaynak kodunda.
mgutt

1
Diğer bazı noktalar: HTML etiketlerini strip_tags()bundan sonra da kaldırırsınız [<>]. Buna göre strip_tags()gerçekten gerekli değil. Aynı nokta alıntılardır. İle çözdüğünüzde tırnak işareti kalmadı ENT_QUOTES. Ve str_replace()ardışık beyaz boşlukları kaldırmaz ve ardından çok strtolower()baytlı dizeler için kullanırsınız . Ve neden hiç küçük harfe dönüştürüyorsunuz? Ve nihayet @BasilMusa'nın bahsettiği gibi ayrılmış bir karakter yakalayamadınız.
Cevabımda

ona aşık oldum!
Yash Kumar Verma

39

ÇÖZÜM 1 - basit ve etkili

$file_name = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $url ) );

  • strtolower (), dosya adının küçük harf olmasını garanti eder (çünkü büyük / küçük harf URL'nin içinde değil, NTFS dosya adında önemli değildir)
  • [^a-z0-9]+ dosya adının yalnızca harfleri ve sayıları
  • Geçersiz karakterlerin yerine '-'dosya adını okunabilir tutar

Misal:

URL:  http://stackoverflow.com/questions/2021624/string-sanitizer-for-filename
File: http-stackoverflow-com-questions-2021624-string-sanitizer-for-filename

ÇÖZÜM 2 - çok uzun URL'ler için

URL içeriklerini önbelleğe almak istiyorsunuz ve sadece benzersiz dosya adlarına sahip olmanız gerekiyor. Bu işlevi kullanırdım:

$file_name = md5( strtolower( $url ) )

bu, sabit uzunlukta bir dosya adı oluşturacaktır. MD5 hash'i çoğu durumda bu tür bir kullanım için yeterince benzersizdir.

Misal:

URL:  https://www.amazon.com/Interstellar-Matthew-McConaughey/dp/B00TU9UFTS/ref=s9_nwrsa_gw_g318_i10_r?_encoding=UTF8&fpl=fresh&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=desktop-1&pf_rd_r=BS5M1H560SMAR2JDKYX3&pf_rd_r=BS5M1H560SMAR2JDKYX3&pf_rd_t=36701&pf_rd_p=6822bacc-d4f0-466d-83a8-2c5e1d703f8e&pf_rd_p=6822bacc-d4f0-466d-83a8-2c5e1d703f8e&pf_rd_i=desktop
File: 51301f3edb513f6543779c3a5433b01c

4
Belki MD5 bir Sorun nedeniyle olabilir: URL'lerle karmalar kullanırken dikkatli olun. URL'lerin skrenta.com/2007/08/md5_tutorial.html sayısının karekökü hala mevcut web boyutundan çok daha büyük olsa da, bir çarpışma olursa sayfalar beklerken Britney Spears hakkında sayfalar alacaksınız. Bugzilla hakkında. Muhtemelen bizim durumumuzda sorun olmayacak, ancak milyarlarca sayfa için SHA 256 gibi çok daha büyük bir karma algoritmayı tercih eder veya bundan tamamen kaçınırdım. Kaynak: boyter.org/2013/01/code-for-a-search-engine-in-php-part-1
adilbo

15

Tempnam () bunu sizin için yapacak.

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

ama bu tamamen yeni bir isim yaratır.

Mevcut bir dizeyi sterilize etmek için, kullanıcılarınızın girebileceklerini kısıtlayın ve harf, sayı, nokta, kısa çizgi ve alt çizgi yapın, ardından basit bir normal ifadeyle sterilize edin. Hangi karakterlerden kaçılması gerektiğini kontrol edin, aksi takdirde yanlış pozitifler alabilirsiniz.

$sanitized = preg_replace('/[^a-zA-Z0-9\-\._]/','', $filename);

13
preg_replace("[^\w\s\d\.\-_~,;:\[\]\(\]]", '', $file)

Sisteminiz için neye izin verildiğine bağlı olarak daha fazla geçerli karakter ekleyin / kaldırın.

Alternatif olarak, dosyayı oluşturmayı deneyebilir ve ardından kötüyse bir hata döndürebilirsiniz.


5
Bu .., sorun olabilecek veya olmayabilecek gibi dosya adlarına izin verir .
Dominic Rodger

@Dom - sabit bir değer olduğu için bunu ayrıca kontrol edin.
Tor Valamo

10

PHP, bir metni farklı biçime dönüştürmek için bir işlev sağlar

filter.filters.sanitize

Nasıl :

echo filter_var(
   "Lorem Ipsum has been the industry's",FILTER_SANITIZE_URL
); 

Blok alıntı LoremIpsumhasbeentheindustry's


1
İyi, ancak eğik çizgileri kaldırmaz, bu bir sorun olabilir: Dizin gezinme.
func0der

7

güvenli: her NOT "a-zA-Z0-9_-" dizisini bir tire ile değiştirin; kendiniz bir uzantı ekleyin.

$name = preg_replace('/[^a-zA-Z0-9_-]+/', '-', strtolower($name)).'.'.$extension;

1
Dosya uzantısını "." İle ayırarak eklemeniz gerekir: $ name = preg_replace ('/ [^ a-zA-Z0-9 _-] + /', '-', strtolower ($ name)). '.' . $ uzantı;
Smith

6

Aşağıdaki ifade güzel, temiz ve kullanılabilir bir dize oluşturur:

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

Torna bugünün finans: faturalama içine Bugün-s-mali-fatura


Yani bir dosya adında nokta veya alt çizgi veya bunun gibi bir şey olamaz?
Tor Valamo

2
@Jonathan - italik ile ne var?
Dominic Rodger

@Tor, evet, üzgünüm. Güncellenmiş. @Dominic, sadece metne vurgu yapıyor.
Sampson

Gism nedir? "Uyarı: preg_replace () [function.preg-replace]: Bilinmeyen değiştirici 'g'"
mesajı alıyorum

1
@ user151841 preg_replaceGlobal bayrak örtüktür . Yani preg_replace kullanılıyorsa g'ye gerek yoktur. Değiştirmelerin sayısını kontrol etmek istediğimizde, preg_replace bunun için bir limitparametreye sahiptir. Daha fazla bilgi için preg_replace belgelerini okuyun.
rineez

6

Tek noktalara izin vermek için Sean Vieira'nın çözümünde küçük bir ayarlama yaparak şunları kullanabilirsiniz:

preg_replace("([^\w\s\d\.\-_~,;:\[\]\(\)]|[\.]{2,})", '', $file)

2

Bunlar biraz ağır olabilir, ancak herhangi bir dizeyi "güvenli" enstil dosya adı veya klasör adı (veya bükerseniz temizlenmiş sümüklü böcek ve benzeri şeyler) olarak sterilize edecek kadar esnektirler .

1) Tam bir dosya adı oluşturma (girdinin tamamen kesilmesi durumunda geri dönüş adıyla):

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

2) Veya tam bir dosya adı oluşturmadan sadece filtre kullanımının kullanılması (katı mod true, dosya adında [] veya () 'a izin vermez):

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

3) Ve işte bu işlevler:

// 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;
    }
}

Diyelim ki bazı kullanıcı girdileri: .....&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) საბეჭდი-და-ტიპოგრაფიული

Dosya adı 255 karakter olan bir tar.gz yapmak için onu daha dostane bir şeye dönüştürmek istiyoruz. İşte örnek bir kullanım. Not: Bu örnek, kavramın bir kanıtı olarak hatalı biçimlendirilmiş bir tar.gz uzantısı içerir, dizge beyaz listelerinize göre oluşturulduktan sonra da ext'i filtrelemelisiniz.

$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);

Çıktı şu şekilde olacaktır: _wei_gbel_file_name_dcor_._._._z_._y_._x_._this_name_is_462_not_that_grrrreat_][09]()1234747)_.tar.gz

Onunla burada oynayabilirsiniz: https://3v4l.org/iSgi8

Veya bir Özet: https://gist.github.com/dhaupin/b109d3a8464239b7754a

DÜZENLEME:&nbsp; alan yerine güncellenmiş komut dosyası filtresi , güncellenmiş 3v4l bağlantısı


1

Bugün bildiğim en iyi yöntem , Nette çerçevesinden Strings :: webalize yöntemidir .

BTW, bu tüm aksan işaretlerini temellerine çevirir .. š => s ü => u ß => ss vb.

Dosya adları için nokta "" eklemeniz gerekir. izin verilen karakterler parametresine.

/**
 * 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;
}

Neden aksanları değiştirmek istiyorsun? urlencode()Dosya adını srcveya olarak kullanmadan önce kullanın href. UTF-8 ile sorunları olan şu anda kullanılan tek dosya sistemi FATx'tir (XBOX tarafından kullanılıyor): en.wikipedia.org/wiki/Comparison_of_file_systems#Limits Ve bunun web sunucuları tarafından kullanıldığını sanmıyorum
mgutt

1

Görünüşe göre tüm bunlar soruya bağlı, bir sunucuyu hacklemek için kullanılabilecek bir dosya adı oluşturmak (veya başka bir zarar vermek) mümkün mü? Değilse, o zaman basit bir cevap, dosyayı nihayetinde kullanılacağı her yerde oluşturmayı denemektir (çünkü bu, hiç şüphesiz tercih edilen işletim sistemi olacaktır). Bırakın işletim sistemi çözsün. Şikayet ederse, şikayeti Kullanıcıya Doğrulama Hatası olarak geri gönderin.

Bu, güvenilir bir şekilde taşınabilir olma avantajına sahiptir, çünkü tüm (oldukça eminim) işletim sistemleri, dosya adı bu işletim sistemi için uygun şekilde biçimlendirilmezse şikayet eder.

O takdirde ise daha az dosya adının tam "sağlık" den karmaşık önlemler - Bir dosya adıyla çirkin şeyler yapmak mümkün, belki ikamet işletim sistemine dosya adı test etmeden önce uygulanabilir tedbirler vardır.


0

tek yön

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

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

}
echo sanitize($string,$bad);

Yazdırılamayan karakterler ne olacak? Bu durumda kara liste yaklaşımından ziyade beyaz liste yaklaşımını kullanmak daha iyidir. Temel olarak, tabii ki özel harfler hariç, yalnızca yazdırılabilir ASCII dosya adlarına izin verin. Ancak İngilizce olmayan yerel ayarlar için bu başka bir sorun.
TheRealChx101

0

/ve ..kullanıcı tarafından sağlanan dosya adı zararlı olabilir. Öyleyse bunlardan şöyle bir şeyle kurtulmalısınız:

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

Bu yetersiz! Örneğin, "./.name" dosya adı halen geçerli dizinden çıkacaktır. (Kaldırmak .. burada hiçbir şey yapmaz, ancak kaldırmak / ./.
Öğesini

3
@ cemper93 Hayır, bu cevap sadece hiçbir şeyden kopmayacak dizeyi çevirecek ..name. Tüm yol ayırıcı karakterlerin kaldırılması, herhangi bir dizin geçişini önlemek için yeterli olmalıdır. (Kaldırılması ..teknik olarak gereksizdir.)
cdhowie

@cdhowie Evet, ancak dosya adı ./.olur ... Ve son olarak bu yanıt, NULL gibi dosya sistemi için ayrılmış diğer tüm karakterleri kaçırır.
Cevabımdan

-4

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

Kullanıcılar eğik çizgiyi iki kelimeyi ayırmak için kullanabileceğinden, NULL yerine kısa çizgi kullanmak daha iyi olacaktır.


NULL ile değiştirileceği nerede söylendi? Ayrıca, bu tüm özel karakterleri işlemez.
Travis Pessetto

Evet - işlemesi gereken başka özel karakterler de var. str_replace burada en iyi teklif olmayacak.
Martin Kovachev
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.