Próbuję wymyślić funkcję, która dobrze radzi sobie z oczyszczaniem niektórych ciągów, tak aby można je było bezpiecznie używać w adresie URL (jak post slug), a także bezpiecznie używać jako nazw plików. Na przykład, gdy ktoś przesyła plik, chcę się upewnić, że usunę wszystkie niebezpieczne znaki z nazwy.
Do tej pory wymyśliłem następującą funkcję, która, mam nadzieję, rozwiązuje ten problem i zezwala również na zagraniczne dane UTF-8.
/**
* Convert a string to the file/URL safe "slug" form
*
* @param string $string the string to clean
* @param bool $is_filename TRUE will allow additional filename characters
* @return string
*/
function sanitize($string = '', $is_filename = FALSE)
{
// Replace all weird characters with dashes
$string = preg_replace('/[^\w\-'. ($is_filename ? '~_\.' : ''). ']+/u', '-', $string);
// Only allow one dash separator at a time (and make string lowercase)
return mb_strtolower(preg_replace('/--+/u', '-', $string), 'UTF-8');
}
Czy ktoś ma jakieś skomplikowane przykładowe dane, z którymi mogę się temu zapoznać - lub zna lepszy sposób ochrony naszych aplikacji przed złymi nazwami?
$ is-filename pozwala na dodatkowe znaki, takie jak pliki temp vim
aktualizacja: usunąłem znak gwiazdy, ponieważ nie mogłem wymyślić prawidłowego użycia
php
url
filenames
sanitization
Xeoncross
źródło
źródło
Odpowiedzi:
Kilka uwag na temat twojego rozwiązania:
Tworzenie ślimaka
Prawdopodobnie nie powinieneś umieszczać znaków akcentowanych itp. W swoim poście, ponieważ technicznie rzecz biorąc, powinny być zakodowane w procentach (według reguł kodowania adresu URL), więc będziesz mieć brzydko wyglądające adresy URL.
Tak więc na twoim miejscu po małych literach zamieniłbym wszystkie znaki „specjalne” na ich odpowiedniki (np. É -> e) i zamieniłbym znaki inne niż [az] na „-”, ograniczając się do ciągów pojedynczego „-” tak jak zrobiłeś. Istnieje implementacja konwersji znaków specjalnych tutaj: https://web.archive.org/web/20130208144021/http://neo22s.com/slug
Ogólnie odkażanie
OWASP ma implementację PHP Enterprise Security API, która obejmuje między innymi metody bezpiecznego kodowania i dekodowania danych wejściowych i wyjściowych w Twojej aplikacji.
Interfejs kodera zapewnia:
https://github.com/OWASP/PHP-ESAPI https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API
źródło
สังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่.txt
a następnie utworzyłem plik HTML UTF-8 z linkiem do niego. Zadziwiająco działało - nawet w oknach! Jednak miałem wtedy PHPfile_put_contents('สังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่.txt')
i nie udało się utworzyć nazwy pliku bazaru z tego ciągu. Potem próbowałem go utworzyć za pomocąfopen()
i otrzymałem tę samą pomieszaną nazwę pliku. Najwyraźniej PHP (przynajmniej w systemie Windows) nie jest w stanie tworzyć nazw plików UTF-8. bugs.php.net/bug.php?id=46990&thanks=6Znalazłem tę większą funkcję w kodzie Chyrpa :
a ten w kodzie wordpress
Aktualizacja wrzesień 2012
Alix Axel wykonał niesamowitą pracę w tej dziedzinie. Jego struktura funkcyjna zawiera kilka świetnych filtrów i transformacji tekstu.
źródło
apply_filters
/[\s-]+/
z-
co jest lepsze niż w pierwszym wariancie (który zastępuje tylko/\s+/
), które mogą powodować wiele kresek rzęduTo powinno sprawić, że twoje nazwy plików będą bezpieczne ...
a głębszym rozwiązaniem tego problemu jest:
Zakłada się, że chcesz mieć kropkę w nazwie pliku. jeśli chcesz, aby były przenoszone na małe litery, po prostu użyj
dla ostatniej linii.
źródło
'ľ' => 'l', 'Ľ' => 'L', 'č' => 'c', 'Č' => 'C', 'ť' => 't', 'Ť' => 'T', 'ň' => 'n', 'Ň' => 'N', 'ĺ' => 'l', 'Ĺ' => 'L', 'Ř' => 'R', 'ř' => 'r', 'ě' => 'e', 'Ě' => 'E', 'ů' => 'u', 'Ů' => 'U'
Spróbuj tego:
Na podstawie odpowiedzi wybranej w tym wątku: Przyjazna nazwa użytkownika w PHP?
źródło
trim()
powinno też byćtrim($string, '-')
.preg_replace()
powinien usunąć wszystkie niebezpieczne znaki.To nie jest dokładna odpowiedź, ponieważ nie dostarcza żadnych rozwiązań (jeszcze!), Ale jest zbyt duża, aby zmieścić się w komentarzu ...
Przeprowadziłem kilka testów (dotyczących nazw plików) na Windows 7 i Ubuntu 12.04 i odkryłem, że:
1. PHP nie obsługuje nazw plików spoza ASCII
Chociaż zarówno Windows, jak i Ubuntu mogą obsługiwać nazwy plików Unicode (nawet te RTL, jak się wydaje), PHP 5.3 wymaga hacków, aby poradzić sobie nawet ze zwykłym starym ISO-8859-1, więc lepiej jest zachować ASCII tylko dla bezpieczeństwa.
2. Długość nazwy pliku ma znaczenie (szczególnie w systemie Windows)
W systemie Ubuntu maksymalna długość, jaką może mieć nazwa pliku (łącznie z rozszerzeniem) to 255 (bez ścieżki):
Jednak w systemie Windows 7 (NTFS) maksymalna długość nazwy pliku zależy od jego ścieżki bezwzględnej:
Wikipedia podaje, że:
Według mojej najlepszej wiedzy (i testów) jest to błędne.
W sumie (licząc ukośniki) wszystkie te przykłady mają 259 znaków, jeśli pozbędziesz się tego,
C:\
co daje 256 znaków (nie 255 ?!). Katalogi zostały utworzone przy użyciu Eksploratora, a zauważysz, że ogranicza się on do wykorzystania całego dostępnego miejsca na nazwę katalogu. Powodem tego jest umożliwienie tworzenia plików przy użyciu rozszerzenia konwencji nazewnictwa plików 8.3 . To samo dzieje się z innymi partycjami.Pliki nie muszą oczywiście rezerwować wymagań dotyczących długości 8.3:
Nie można utworzyć więcej podkatalogów, jeśli bezwzględna ścieżka katalogu nadrzędnego ma więcej niż 242 znaki, ponieważ
256 = 242 + 1 + \ + 8 + . + 3
. Używając Eksploratora Windows, nie możesz utworzyć innego katalogu, jeśli katalog nadrzędny ma więcej niż 233 znaki (w zależności od ustawień regionalnych systemu), ponieważ256 = 233 + 10 + \ + 8 + . + 3
;10
tutaj jest długość łańcuchaNew folder
.System plików Windows stwarza nieprzyjemny problem, jeśli chcesz zapewnić współdziałanie między systemami plików.
3. Uważaj na zastrzeżone znaki i słowa kluczowe
Oprócz usuwania znaków spoza ASCII, niedrukowalnych i kontrolnych , musisz również ponownie (umieść / przenieś):
Samo usunięcie tych znaków może nie być najlepszym pomysłem, ponieważ nazwa pliku może stracić na znaczeniu. Myślę, że przynajmniej wielokrotne występowanie tych znaków powinno być zastąpione pojedynczym podkreśleniem (
_
), a może czymś bardziej reprezentatywnym (to tylko pomysł):"*?
->_
/\|
->-
:
->[ ]-[ ]
<
->(
>
->)
Istnieją również specjalne słowa kluczowe, których należy unikać (np.
NUL
), Chociaż nie jestem pewien, jak to przezwyciężyć. Być może czarna lista z przypadkową nazwą zastępczą byłaby dobrym podejściem do rozwiązania tego problemu.4. Wrażliwość wielkości liter
To powinno być oczywiste, ale jeśli chcesz, aby zapewnić unikalność plików w różnych systemach operacyjnych, powinieneś przekształcić nazwy plików do znormalizowanej wielkości, w ten sposób
my_file.txt
iMy_File.txt
na Linuksie nie będą oba takie samemy_file.txt
plikiem w systemie Windows.5. Upewnij się, że jest wyjątkowy
Jeśli nazwa pliku już istnieje, do podstawowej nazwy pliku należy dołączyć unikalny identyfikator .
Typowe unikalne identyfikatory obejmują sygnaturę czasową systemu UNIX, skrót zawartości pliku lub losowy ciąg.
6. Ukryte pliki
To, że można go nazwać, nie oznacza, że powinno ...
Kropki są zwykle wyświetlane na biało w nazwach plików, ale w systemie Linux ukryty plik jest reprezentowany przez wiodącą kropkę.
7. Inne kwestie
Jeśli musisz usunąć niektóre znaki z nazwy pliku, rozszerzenie jest zwykle ważniejsze niż podstawowa nazwa pliku. Dopuszczając znaczną maksymalną liczbę znaków dla rozszerzenia pliku (8-16) należy usunąć znaki z nazwy bazowej. Należy również zauważyć, że w mało prawdopodobnym przypadku posiadania więcej niż jednego długiego rozszerzenia - takiego jak
_.graphmlz.tag.gz
-_.graphmlz.tag
tylko_
w tym przypadku należy traktować jako nazwę bazową pliku.8. Zasoby
Calibre całkiem przyzwoicie radzi sobie ze zniekształcaniem nazw plików:
Strona Wikipedii dotycząca zniekształcania nazw plików i połączonego rozdziału z Korzystanie z Samby .
Jeśli na przykład spróbujesz utworzyć plik, który narusza którąkolwiek z zasad 1/2/3, otrzymasz bardzo przydatny błąd:
źródło
Zawsze myślałem, że Kohana całkiem nieźle się spisała .
Poręczny
UTF8::transliterate_to_ascii()
zmieni rzeczy takie jak ñ => n.Oczywiście możesz zastąpić inne
UTF8::*
rzeczy funkcjami mb_ *.źródło
Jeśli chodzi o przesyłanie plików, najbezpieczniej byłoby uniemożliwić użytkownikowi kontrolowanie nazwy pliku. Jak już wspomniano, przechowuj kanonizowaną nazwę pliku w bazie danych wraz z losowo wybraną i unikalną nazwą, której będziesz używać jako rzeczywistej nazwy pliku.
Używając OWASP ESAPI, nazwy te można wygenerować w ten sposób:
Możesz dołączyć sygnaturę czasową do $ safeFilename, aby upewnić się, że losowo wygenerowana nazwa pliku jest unikalna, nawet bez sprawdzania istniejącego pliku.
Jeśli chodzi o kodowanie adresów URL i ponownie przy użyciu ESAPI:
Ta metoda przeprowadza kanonizację przed zakodowaniem ciągu i obsługuje wszystkie kodowania znaków.
źródło
Polecam * URLify dla PHP (ponad 480 gwiazdek na Github) - "port PHP URLify.js z projektu Django. Transliteracja znaków innych niż ASCII do użycia w adresach URL".
Podstawowe użycie:
Aby wygenerować informacje o błędach dla adresów URL:
Aby wygenerować informacje o błędach dla nazw plików:
* Żadna z pozostałych sugestii nie spełniła moich kryteriów:
Dodatkowo, URLify usuwa również określone słowa i usuwa wszystkie znaki niepoddane transliteracji.
Oto przypadek testowy z tonami obcych znaków poprawnie transliterowanych za pomocą URLify: https://gist.github.com/motin/a65e6c1cc303e46900d10894bf2da87f
źródło
Zaadaptowałem z innego źródła i dodałem kilka dodatkowych, może trochę przesadzonych
źródło
a to jest wersja Joomla 3.3.2 z
JFile::makeSafe($file)
źródło
Nie sądzę, aby posiadanie listy znaków do usunięcia nie było bezpieczne. Wolałbym raczej użyć następujących:
W przypadku nazw plików: użyj wewnętrznego identyfikatora lub skrótu zawartości pliku. Zapisz nazwę dokumentu w bazie danych. W ten sposób możesz zachować oryginalną nazwę pliku i nadal go znaleźć.
W przypadku parametrów adresu URL: służy
urlencode()
do kodowania wszelkich znaków specjalnych.źródło
W zależności od tego, jak będziesz go używać, możesz chcieć dodać limit długości, aby chronić przed przepełnieniem bufora.
źródło
To dobry sposób na zabezpieczenie nazwy pliku do przesłania:
źródło
.\x00..\x20
można się sprowadzić.\x00\x20
..\x00..\x20
usuwa kropki i każdy znak między\x00
a\x20
, podczas gdy.\x00\x20
powinno usuwać tylko te 3 bajty.Oto implementacja CodeIgnitera.
I
remove_invisible_characters
zależność.źródło
dlaczego po prostu nie użyć php
urlencode
? zastępuje „niebezpieczne” znaki ich reprezentacją szesnastkową dla adresów URL (np.%20
dla spacji)źródło
Istnieje już kilka rozwiązań dla tego pytania, ale przeczytałem i przetestowałem większość kodu tutaj i skończyło się na tym rozwiązaniu, które jest mieszanką tego, czego się tutaj nauczyłem:
Funkcja
Funkcja jest dołączona tutaj w pakiecie Symfony2, ale można ją wyodrębnić do użycia jako zwykły PHP , ma tylko zależność od
iconv
funkcji, która musi być włączona:Filesystem.php :
Testy jednostkowe
Co ciekawe, stworzyłem testy PHPUnit, najpierw do testowania skrajnych przypadków, więc możesz sprawdzić, czy pasuje do twoich potrzeb: (Jeśli znajdziesz błąd, możesz dodać przypadek testowy)
FilesystemTest.php :
Wyniki testu: (sprawdzone na Ubuntu z PHP 5.3.2 i MacOsX z PHP 5.3.17:
źródło
Mam tytuły wpisów z wszelkiego rodzaju dziwnymi znakami łacińskimi, a także kilka tagów HTML, które musiałem przetłumaczyć na przydatny format nazwy pliku rozdzielany myślnikami. Połączyłem odpowiedź @ SoLoGHoST z kilkoma elementami z odpowiedzi @ Xeoncross i trochę dostosowałem.
Musiałem ręcznie dodać znak myślnika (-) do tablicy tłumaczenia. Mogą być inne, ale jak dotąd moje nazwy plików wyglądają dobrze.
Więc:
Część 1: „Žurburts” mojego taty? - są (nie) najlepsze!
staje się:
część-1-moi-tatusiowie-zurburty-nie-najlepsi
Po prostu dodaję „.html” do zwróconego ciągu.
źródło
'ľ' => 'l', 'Ľ' => 'L', 'č' => 'c', 'Č' => 'C', 'ť' => 't', 'Ť' => 'T', 'ň' => 'n', 'Ň' => 'N', 'ĺ' => 'l', 'Ĺ' => 'L', 'Ř' => 'R', 'ř' => 'r', 'ě' => 'e', 'Ě' => 'E', 'ů' => 'u', 'Ů' => 'U'
$string = transliterator_transliterate('Any-Latin;Latin-ASCII;', $string);
Zobacz moją odpowiedź poniżej lub przeczytaj link do wpisu na blogu.Rozwiązanie nr 1: Masz możliwość instalowania rozszerzeń PHP na serwerze (hosting)
Do transliteracji „prawie każdego języka na Ziemi” do znaków ASCII.
Najpierw zainstaluj rozszerzenie PHP Intl . To jest polecenie dla Debiana (Ubuntu):
sudo aptitude install php5-intl
To jest moja funkcja fileName (utwórz test.php i wklej następujący kod):
Ta linia jest rdzeniem:
Odpowiedz na podstawie tego postu .
Rozwiązanie nr 2: Nie masz możliwości instalowania rozszerzeń PHP na serwerze (hosting)
Całkiem niezła robota jest wykonana w module transliteracji dla CMS Drupal. Obsługuje prawie każdy język na Ziemi. Proponuję sprawdzić repozytorium wtyczek, jeśli chcesz mieć naprawdę kompletne ciągi czyszczące rozwiązanie.
źródło
Ten post wydaje się działać najlepiej ze wszystkich, które powiązałem. http://gsynuh.com/php-string-filename-url-safe/205
źródło
To dobra funkcja:
źródło
\\s+
oznacza ukośnik odwrotny, po którym następuje jedna lub więcej białych znaków. O czym to jest? Ponadto wykorzystuje to czarną listę zamiast białej listy, ignorując takie rzeczy jakCMD
, null lubBEL
./blog/2014-02/just-in-time
nie są dozwolone. Skorzystaj z testowanego kodu powyżej lub użyjphunction
kodu struktury PHP.preg_replace('~[^\-\pL\pN\s]+~u', '-', $string)
Oto kod używany przez Prestashop do oczyszczania adresów URL:
jest używany przez
aby usunąć znaki diakrytyczne
źródło
Istnieją 2 dobre odpowiedzi, aby spowolnić swoje dane, użyj go https://stackoverflow.com/a/3987966/971619 lub https://stackoverflow.com/a/7610586/971619
źródło
źródło