Sanitasi string agar URL dan nama filenya aman?

137

Saya mencoba untuk menemukan fungsi yang melakukan pekerjaan yang baik untuk membersihkan string tertentu sehingga aman digunakan di URL (seperti siput pos) dan juga aman digunakan sebagai nama file. Misalnya, ketika seseorang mengupload file, saya ingin memastikan bahwa saya menghapus semua karakter berbahaya dari namanya.

Sejauh ini saya telah menemukan fungsi berikut yang saya harap dapat memecahkan masalah ini dan juga memungkinkan data UTF-8 asing.

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

Adakah yang punya data sampel rumit yang dapat saya gunakan untuk melawan ini - atau mengetahui cara yang lebih baik untuk melindungi aplikasi kita dari nama yang buruk?

$ is-filename memungkinkan beberapa karakter tambahan seperti file temp vim

pembaruan: menghapus karakter bintang karena saya tidak dapat memikirkan penggunaan yang valid

Xeoncross
sumber
Lebih baik Anda menghapus semuanya kecuali [\ w.-]
elias
3
Anda mungkin menemukan Normalizer dan komentar di atasnya berguna.
Matt Gibson

Jawaban:

57

Beberapa pengamatan tentang solusi Anda:

  1. 'u' di akhir pola berarti pola tersebut , dan bukan teks yang cocok akan ditafsirkan sebagai UTF-8 (Saya anggap Anda menganggap yang terakhir?).
  2. \ w cocok dengan karakter garis bawah. Anda secara khusus menyertakannya untuk file yang mengarah pada asumsi bahwa Anda tidak menginginkannya di URL, tetapi dalam kode yang Anda miliki URL akan diizinkan untuk menyertakan garis bawah.
  3. Dimasukkannya "UTF-8 asing" tampaknya bergantung pada lokal. Tidak jelas apakah ini lokal server atau klien. Dari dokumen PHP:

Karakter "kata" adalah setiap huruf atau angka atau karakter garis bawah, yaitu, karakter apa pun yang dapat menjadi bagian dari "kata" Perl. Definisi huruf dan angka dikontrol oleh tabel karakter PCRE, dan dapat bervariasi jika pencocokan khusus lokal dilakukan. Misalnya, dalam lokal "fr" (Prancis), beberapa kode karakter yang lebih besar dari 128 digunakan untuk huruf beraksen, dan ini dicocokkan dengan \ w.

Menciptakan siput

Anda mungkin tidak boleh memasukkan karakter beraksen dll dalam siput posting Anda karena, secara teknis, mereka harus dikodekan persen (per aturan pengkodean URL) sehingga Anda akan memiliki URL yang terlihat jelek.

Jadi, jika saya jadi Anda, setelah huruf kecil, saya akan mengonversi karakter 'khusus' apa pun ke padanannya (misalnya é -> e) dan mengganti karakter non [az] dengan '-', membatasi berjalannya satu '-' seperti yang Anda lakukan. Ada implementasi untuk mengonversi karakter khusus di sini: https://web.archive.org/web/20130208144021/http://neo22s.com/slug

Sanitasi secara umum

OWASP memiliki implementasi PHP untuk Enterprise Security API mereka yang antara lain mencakup metode untuk encoding dan decoding input dan output yang aman dalam aplikasi Anda.

Antarmuka Encoder menyediakan:

canonicalize (string $input, [bool $strict = true])
decodeFromBase64 (string $input)
decodeFromURL (string $input)
encodeForBase64 (string $input, [bool $wrap = false])
encodeForCSS (string $input)
encodeForHTML (string $input)
encodeForHTMLAttribute (string $input)
encodeForJavaScript (string $input)
encodeForOS (Codec $codec, string $input)
encodeForSQL (Codec $codec, string $input)
encodeForURL (string $input)
encodeForVBScript (string $input)
encodeForXML (string $input)
encodeForXMLAttribute (string $input)
encodeForXPath (string $input)

https://github.com/OWASP/PHP-ESAPI https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API

Alan Donnelly
sumber
Anda benar tentang asumsi saya tentang pengubah "u" - saya pikir itu untuk teks. Saya juga lupa tentang pengubah \ w termasuk garis bawah. Saya biasanya akan mengonversi semua karakter beraksen ke ASCII - tetapi saya ingin ini berfungsi untuk bahasa lain juga. Saya berasumsi bahwa akan ada semacam cara aman UTF-8 bahwa karakter bahasa apa pun dapat digunakan dalam siput URL atau nama file sehingga bahkan judul bahasa Arab pun akan berfungsi. Bagaimanapun, linux mendukung nama file UTF-8 dan browser harus menyandikan tautan HTML sesuai kebutuhan. Terima kasih banyak atas masukan Anda di sini.
Xeoncross
Setelah dipikir-pikir, Anda sebenarnya benar, tetapi ini bukan hanya masalah browser yang mengkodekan tautan dengan benar. Cara termudah untuk mencapai apa yang Anda inginkan adalah dengan memetakan karakter non-ASCII ke ASCII terdekat yang setara dan kemudian menyandikan URL tautan Anda di badan HTML. Cara yang sulit adalah memastikan pengkodean UTF-8 yang konsisten (atau UTF-16, menurut saya untuk beberapa dialek Cina) dari penyimpanan data Anda, melalui server web Anda, lapisan aplikasi (PHP), konten halaman, browser web dan bukan urlencode url Anda ( tapi tetap menghapus karakter 'yang tidak diinginkan'). Ini akan memberi Anda tautan dan URL non-encoded yang bagus.
Alan Donnelly
Saran yang bagus. Saya akan mencoba membuat lingkungan UTF-8 murni. Kemudian, mengambil beberapa string dari bahasa non-ASCII, saya akan menghapus karakter berbahaya (./ ;: dll ...) dan membuat file dan kemudian menautkan HTML ke file tersebut untuk melihat apakah saya dapat mengkliknya dan melihat apakah semua ini bekerja. Jika tidak, saya mungkin harus kembali ke (raw)? Urlencode () untuk mengizinkan UTF-8. Saya akan memposting kembali hasil di sini.
Xeoncross
3
Saya membuat file bernama สังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่.txtdan kemudian membuat file HTML UTF-8 dengan tautan ke sana. Hebatnya itu berhasil - bahkan di windows! Namun, saya kemudian memiliki PHP file_put_contents('สังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่.txt')dan gagal membuat nama file bazaar dari string itu. Kemudian saya mencoba membuatnya dengan fopen()dan mendapatkan nama file yang sama. Jadi rupanya PHP (setidaknya di windows) tidak mampu membuat nama file UTF-8. bugs.php.net/bug.php?id=46990&thanks=6
Xeoncross
1
Saya menghadiahkan jawaban ini karena membuat saya paling banyak berpikir dan juga menyertakan tautan berguna ke proyek yang belum pernah saya dengar yang layak untuk dilihat. Saya akan memposting begitu saya menemukan jawabannya.
Xeoncross
90

Saya menemukan fungsi yang lebih besar ini dalam kode Chyrp :

/**
 * Function: sanitize
 * Returns a sanitized string, typically for URLs.
 *
 * Parameters:
 *     $string - The string to sanitize.
 *     $force_lowercase - Force the string to lowercase?
 *     $anal - If set to *true*, will remove all non-alphanumeric characters.
 */
function sanitize($string, $force_lowercase = true, $anal = false) {
    $strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
                   "}", "\\", "|", ";", ":", "\"", "'", "‘", "’", "“", "”", "–", "—",
                   "—", "–", ",", "<", ".", ">", "/", "?");
    $clean = trim(str_replace($strip, "", strip_tags($string)));
    $clean = preg_replace('/\s+/', "-", $clean);
    $clean = ($anal) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ;
    return ($force_lowercase) ?
        (function_exists('mb_strtolower')) ?
            mb_strtolower($clean, 'UTF-8') :
            strtolower($clean) :
        $clean;
}

dan yang ini di kode wordpress

/**
 * Sanitizes a filename replacing whitespace with dashes
 *
 * Removes special characters that are illegal in filenames on certain
 * operating systems and special characters requiring special escaping
 * to manipulate at the command line. Replaces spaces and consecutive
 * dashes with a single dash. Trim period, dash and underscore from beginning
 * and end of filename.
 *
 * @since 2.1.0
 *
 * @param string $filename The filename to be sanitized
 * @return string The sanitized filename
 */
function sanitize_file_name( $filename ) {
    $filename_raw = $filename;
    $special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}");
    $special_chars = apply_filters('sanitize_file_name_chars', $special_chars, $filename_raw);
    $filename = str_replace($special_chars, '', $filename);
    $filename = preg_replace('/[\s-]+/', '-', $filename);
    $filename = trim($filename, '.-_');
    return apply_filters('sanitize_file_name', $filename, $filename_raw);
}

Perbarui Sept 2012

Alix Axel telah melakukan beberapa pekerjaan luar biasa di bidang ini. Kerangka kerja fungsinya mencakup beberapa filter dan transformasi teks yang hebat.

Xeoncross
sumber
23
Kode WordPress tidak portabel karena digunakanapply_filters
Kevin Mark
1
Perhatikan bahwa versi wordpress menggantikan /[\s-]+/dengan -yang lebih baik dari versi pertama (yang hanya menggantikan /\s+/) yang dapat menyebabkan beberapa tanda hubung berturut
Yotam Omer
Hanya untuk referensi wordpress apply_filters dapat ditemukan di sini dan sanitize_file_name di sini .
Eric
bagaimana dengan banyak spasi? Ganti
Jeffrey the Giraffe
9
$ Anal -variable terdengar sangat menakutkan bagi saya dengan opsi-paksa.
viljun
30

Ini harus membuat nama file Anda aman ...

$string = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $string);

dan solusi yang lebih dalam untuk ini adalah:

// Remove special accented characters - ie. sí.
$clean_name = strtr($string, array('Š' => 'S','Ž' => 'Z','š' => 's','ž' => 'z','Ÿ' => 'Y','À' => 'A','Á' => 'A','Â' => 'A','Ã' => 'A','Ä' => 'A','Å' => 'A','Ç' => 'C','È' => 'E','É' => 'E','Ê' => 'E','Ë' => 'E','Ì' => 'I','Í' => 'I','Î' => 'I','Ï' => 'I','Ñ' => 'N','Ò' => 'O','Ó' => 'O','Ô' => 'O','Õ' => 'O','Ö' => 'O','Ø' => 'O','Ù' => 'U','Ú' => 'U','Û' => 'U','Ü' => 'U','Ý' => 'Y','à' => 'a','á' => 'a','â' => 'a','ã' => 'a','ä' => 'a','å' => 'a','ç' => 'c','è' => 'e','é' => 'e','ê' => 'e','ë' => 'e','ì' => 'i','í' => 'i','î' => 'i','ï' => 'i','ñ' => 'n','ò' => 'o','ó' => 'o','ô' => 'o','õ' => 'o','ö' => 'o','ø' => 'o','ù' => 'u','ú' => 'u','û' => 'u','ü' => 'u','ý' => 'y','ÿ' => 'y'));
$clean_name = strtr($clean_name, array('Þ' => 'TH', 'þ' => 'th', 'Ð' => 'DH', 'ð' => 'dh', 'ß' => 'ss', 'Œ' => 'OE', 'œ' => 'oe', 'Æ' => 'AE', 'æ' => 'ae', 'µ' => 'u'));

$clean_name = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $clean_name);

Ini mengasumsikan bahwa Anda menginginkan titik di nama file. kalau mau dipindahkan ke huruf kecil, pakai saja

$clean_name = strtolower($clean_name);

untuk baris terakhir.

SoLoGHoST
sumber
1
Masih kehilangan beberapa karakter Ceko dan Slowakia:'ľ' => 'l', 'Ľ' => 'L', 'č' => 'c', 'Č' => 'C', 'ť' => 't', 'Ť' => 'T', 'ň' => 'n', 'Ň' => 'N', 'ĺ' => 'l', 'Ĺ' => 'L', 'Ř' => 'R', 'ř' => 'r', 'ě' => 'e', 'Ě' => 'E', 'ů' => 'u', 'Ů' => 'U'
Jasom Dotnet
22

Coba ini:

function normal_chars($string)
{
    $string = htmlentities($string, ENT_QUOTES, 'UTF-8');
    $string = preg_replace('~&([a-z]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i', '$1', $string);
    $string = html_entity_decode($string, ENT_QUOTES, 'UTF-8');
    $string = preg_replace(array('~[^0-9a-z]~i', '~[ -]+~'), ' ', $string);

    return trim($string, ' -');
}

Examples:

echo normal_chars('Álix----_Ãxel!?!?'); // Alix Axel
echo normal_chars('áéíóúÁÉÍÓÚ'); // aeiouAEIOU
echo normal_chars('üÿÄËÏÖÜŸåÅ'); // uyAEIOUYaA

Berdasarkan jawaban yang dipilih di utas ini: Nama Pengguna URL Ramah di PHP?

John Conde
sumber
Sangat bagus - Saya belum pernah melihat ini dilakukan tanpa tabel terjemahan (seperti penggunaan wordpress). Namun, menurut saya fungsi ini tidak cukup apa adanya karena hanya menerjemahkan karakter khusus tetapi tidak menghapus karakter berbahaya. Mungkin dapat ditambahkan ke salah satu di atas ...
Xeoncross
4
Ha! Peretasan pengkodean entitas itu manis! Meskipun sekilas sama sekali tidak jelas bagaimana metode ini melakukan apa yang dilakukannya. Tapi ada masalah. Tidakkah "Frédéric & Éric" akan berubah menjadi "Frederic amp Eric"?
Alan Donnelly
@AlanDonnelly: Memang, saya telah memperbarui fungsi dalam jawaban asli saya (periksa tautannya), trim()seharusnya juga begitu trim($string, '-').
Alix Axel
@ Xeoncross: Yang terakhir preg_replace()harus menghapus semua karakter berbahaya.
Alix Axel
@AlixAxel, Anda berada di mana saja, bukan Anda. Saya baru saja membaca PHP AWS SDK dan mereka memiliki beberapa kode Anda untuk UUID. Kode phunction yang luar biasa sulit dikalahkan.
Xeoncross
13

Ini bukan jawaban yang tepat karena belum memberikan solusi apa pun (belum!), Tapi terlalu besar untuk muat dalam komentar ...


Saya melakukan beberapa pengujian (mengenai nama file) pada Windows 7 dan Ubuntu 12.04 dan yang saya temukan adalah:

1. PHP Tidak Dapat Menangani Nama File non-ASCII

Meskipun Windows dan Ubuntu dapat menangani nama file Unicode (bahkan yang RTL seperti yang terlihat) PHP 5.3 memerlukan peretasan untuk menangani bahkan dengan ISO-8859-1 yang biasa saja, jadi lebih baik menyimpannya ASCII hanya untuk keamanan.

2. The Lenght of the Filename Matters (Khusus di Windows)

Di Ubuntu, panjang maksimum nama file yang dapat dimiliki (termasuk ekstensi) adalah 255 (tidak termasuk jalur):

/var/www/uploads/123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345/

Namun, pada Windows 7 (NTFS), panjang maksimum nama file bergantung pada jalur absolutnya:

(0 + 0 + 244 + 11 chars) C:\1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234\1234567.txt
(0 + 3 + 240 + 11 chars) C:\123\123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\1234567.txt
(3 + 3 + 236 + 11 chars) C:\123\456\12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\1234567.txt

Wikipedia mengatakan bahwa:

NTFS memungkinkan setiap komponen path (direktori atau nama file) menjadi 255 karakter.

Sejauh pengetahuan saya (dan pengujian), ini salah.

Secara total (menghitung garis miring) semua contoh ini memiliki 259 karakter, jika Anda menghapus C:\yang memberikan 256 karakter (bukan 255 ?!). Direktori di mana dibuat menggunakan Explorer dan Anda akan melihat bahwa itu menahan diri dari menggunakan semua ruang yang tersedia untuk nama direktori. Alasannya adalah untuk memungkinkan pembuatan file menggunakan konvensi penamaan file 8.3 . Hal yang sama terjadi untuk partisi lain.

File tidak perlu memiliki persyaratan panjang 8.3 tentu saja:

(255 chars) E:\12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901.txt

Anda tidak dapat membuat lebih banyak sub-direktori jika path absolut dari direktori induk memiliki lebih dari 242 karakter, karena 256 = 242 + 1 + \ + 8 + . + 3. Dengan menggunakan Windows Explorer, Anda tidak dapat membuat direktori lain jika direktori induk memiliki lebih dari 233 karakter (tergantung pada sistem lokal), karena 256 = 233 + 10 + \ + 8 + . + 3; yang 10di sini adalah panjang string New folder.

Sistem file Windows menimbulkan masalah besar jika Anda ingin memastikan interoperabilitas antar sistem file.

3. Waspadai Karakter dan Kata Kunci yang Dicadangkan

Selain menghapus karakter non-ASCII, tidak dapat dicetak, dan kontrol , Anda juga perlu kembali (tempat / pindahkan):

"*/:<>?\|

Hanya menghapus karakter ini mungkin bukan ide terbaik karena nama file mungkin kehilangan sebagian artinya. Saya pikir, setidaknya, beberapa kemunculan karakter ini harus diganti dengan satu garis bawah ( _), atau mungkin sesuatu yang lebih representatif (ini hanya sebuah ide):

  • "*? -> _
  • /\| -> -
  • : -> [ ]-[ ]
  • < -> (
  • > -> )

Ada juga kata kunci khusus yang harus dihindari (like NUL), walaupun saya tidak yakin bagaimana cara mengatasinya. Mungkin daftar hitam dengan penggantian nama acak akan menjadi pendekatan yang baik untuk menyelesaikannya.

4. Sensitivitas Kasus

Ini seharusnya tidak perlu dikatakan lagi, tetapi jika Anda ingin memastikan keunikan file di berbagai sistem operasi yang berbeda Anda harus mengubah nama file menjadi kasus yang dinormalisasi, dengan cara itu my_file.txtdan My_File.txtdi Linux tidak akan keduanya menjadi my_file.txtfile yang sama di Windows.

5. Pastikan Itu Unik

Jika nama file sudah ada, pengenal unik harus ditambahkan ke nama file dasarnya.

Pengenal unik yang umum termasuk stempel waktu UNIX, intisari konten file, atau string acak.

6. File Tersembunyi

Hanya karena bisa diberi nama bukan berarti harus ...

Titik biasanya tercantum dalam daftar putih dalam nama file, tetapi di Linux, file tersembunyi diwakili oleh titik di depan.

7. Pertimbangan Lain

Jika Anda harus menghapus beberapa karakter dari nama file, ekstensi biasanya lebih penting daripada nama dasar file. Membiarkan sejumlah besar karakter maksimum untuk ekstensi file (8-16) seseorang harus menghapus karakter dari nama dasar. Penting juga untuk dicatat bahwa jika memiliki lebih dari satu ekstensi panjang - seperti _.graphmlz.tag.gz- _.graphmlz.taghanya _harus dianggap sebagai nama basis file dalam kasus ini.

8. Sumberdaya

Kaliber menangani nama file yang rusak dengan cukup baik:

Halaman Wikipedia tentang mangling nama file dan bab terkait dari Menggunakan Samba .


Misalnya, jika Anda mencoba membuat file yang melanggar salah satu aturan 1/2/3, Anda akan mendapatkan kesalahan yang sangat berguna:

Warning: touch(): Unable to create file ... because No error in ... on line ...
Alix Axel
sumber
11

Saya selalu berpikir Kohana melakukan pekerjaannya dengan cukup baik .

public static function title($title, $separator = '-', $ascii_only = FALSE)
{
if ($ascii_only === TRUE)
{
// Transliterate non-ASCII characters
$title = UTF8::transliterate_to_ascii($title);

// Remove all characters that are not the separator, a-z, 0-9, or whitespace
$title = preg_replace('![^'.preg_quote($separator).'a-z0-9\s]+!', '', strtolower($title));
}
else
{
// Remove all characters that are not the separator, letters, numbers, or whitespace
$title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', UTF8::strtolower($title));
}

// Replace all separator characters and whitespace by a single separator
$title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title);

// Trim separators from the beginning and end
return trim($title, $separator);
}

Berguna UTF8::transliterate_to_ascii() akan mengubah hal-hal seperti ñ => n.

Tentu saja, Anda bisa mengganti UTF8::*barang lain dengan fungsi mb_ *.

alex
sumber
5

Dalam hal unggahan file, paling aman Anda adalah mencegah pengguna mengontrol nama file. Seperti yang telah diisyaratkan, simpan nama file yang dikanonikalisasi dalam database bersama dengan nama yang dipilih secara acak dan unik yang akan Anda gunakan sebagai nama file yang sebenarnya.

Menggunakan OWASP ESAPI, nama-nama ini dapat dibuat sebagai berikut:

$userFilename   = ESAPI::getEncoder()->canonicalize($input_string);
$safeFilename   = ESAPI::getRandomizer()->getRandomFilename();

Anda dapat menambahkan stempel waktu ke $ safeFilename untuk membantu memastikan bahwa nama file yang dibuat secara acak itu unik bahkan tanpa memeriksa file yang ada.

Dalam hal pengkodean untuk URL, dan sekali lagi menggunakan ESAPI:

$safeForURL     = ESAPI::getEncoder()->encodeForURL($input_string);

Metode ini melakukan kanonikalisasi sebelum mengenkode string dan akan menangani semua encoding karakter.

jah
sumber
Pastinya - juga, mengambil kendali nama file dari pengguna akan mencegah kemungkinan 2 unggahan memiliki nama yang sama.
CodeVirtuoso
5

Saya merekomendasikan * URLify untuk PHP (480+ bintang di Github) - "port PHP URLify.js dari proyek Django. Menerjemahkan karakter non-ascii untuk digunakan dalam URL".

Penggunaan dasar:

Untuk menghasilkan siput untuk URL:

<?php

echo URLify::filter (' J\'étudie le français ');
// "jetudie-le-francais"

echo URLify::filter ('Lo siento, no hablo español.');
// "lo-siento-no-hablo-espanol"

?>

Untuk menghasilkan siput untuk nama file:

<?php

echo URLify::filter ('фото.jpg', 60, "", true);
// "foto.jpg"

?>

* Tidak ada saran lain yang cocok dengan kriteria saya:

  • Harus dapat diinstal melalui komposer
  • Seharusnya tidak bergantung pada iconv karena berperilaku berbeda pada sistem yang berbeda
  • Harus dapat diperpanjang untuk memungkinkan penggantian dan penggantian karakter kustom
  • Populer (misalnya banyak bintang di Github)
  • Memiliki tes

Sebagai bonus, URLify juga menghapus kata-kata tertentu dan menghapus semua karakter yang tidak ditransliterasi.

Berikut adalah kasus uji dengan banyak karakter asing yang ditransliterasi dengan benar menggunakan URLify: https://gist.github.com/motin/a65e6c1cc303e46900d10894bf2da87f

Motin
sumber
1
Terima kasih - itu terlihat ideal untuk tujuan saya.
David Goodwin
5

Saya telah mengadaptasi dari sumber lain dan menambahkan beberapa tambahan, mungkin sedikit berlebihan

/**
 * Convert a string into a url safe address.
 *
 * @param string $unformatted
 * @return string
 */
public function formatURL($unformatted) {

    $url = strtolower(trim($unformatted));

    //replace accent characters, forien languages
    $search = array('À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', 'Ā', 'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ć', 'ć', 'Ĉ', 'ĉ', 'Ċ', 'ċ', 'Č', 'č', 'Ď', 'ď', 'Đ', 'đ', 'Ē', 'ē', 'Ĕ', 'ĕ', 'Ė', 'ė', 'Ę', 'ę', 'Ě', 'ě', 'Ĝ', 'ĝ', 'Ğ', 'ğ', 'Ġ', 'ġ', 'Ģ', 'ģ', 'Ĥ', 'ĥ', 'Ħ', 'ħ', 'Ĩ', 'ĩ', 'Ī', 'ī', 'Ĭ', 'ĭ', 'Į', 'į', 'İ', 'ı', 'IJ', 'ij', 'Ĵ', 'ĵ', 'Ķ', 'ķ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', 'Ľ', 'ľ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'Ń', 'ń', 'Ņ', 'ņ', 'Ň', 'ň', 'ʼn', 'Ō', 'ō', 'Ŏ', 'ŏ', 'Ő', 'ő', 'Œ', 'œ', 'Ŕ', 'ŕ', 'Ŗ', 'ŗ', 'Ř', 'ř', 'Ś', 'ś', 'Ŝ', 'ŝ', 'Ş', 'ş', 'Š', 'š', 'Ţ', 'ţ', 'Ť', 'ť', 'Ŧ', 'ŧ', 'Ũ', 'ũ', 'Ū', 'ū', 'Ŭ', 'ŭ', 'Ů', 'ů', 'Ű', 'ű', 'Ų', 'ų', 'Ŵ', 'ŵ', 'Ŷ', 'ŷ', 'Ÿ', 'Ź', 'ź', 'Ż', 'ż', 'Ž', 'ž', 'ſ', 'ƒ', 'Ơ', 'ơ', 'Ư', 'ư', 'Ǎ', 'ǎ', 'Ǐ', 'ǐ', 'Ǒ', 'ǒ', 'Ǔ', 'ǔ', 'Ǖ', 'ǖ', 'Ǘ', 'ǘ', 'Ǚ', 'ǚ', 'Ǜ', 'ǜ', 'Ǻ', 'ǻ', 'Ǽ', 'ǽ', 'Ǿ', 'ǿ'); 
    $replace = array('A', 'A', 'A', 'A', 'A', 'A', 'AE', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 's', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'y', 'A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'D', 'd', 'D', 'd', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'IJ', 'ij', 'J', 'j', 'K', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'l', 'l', 'N', 'n', 'N', 'n', 'N', 'n', 'n', 'O', 'o', 'O', 'o', 'O', 'o', 'OE', 'oe', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 'T', 't', 'T', 't', 'T', 't', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'W', 'w', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 's', 'f', 'O', 'o', 'U', 'u', 'A', 'a', 'I', 'i', 'O', 'o', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'A', 'a', 'AE', 'ae', 'O', 'o'); 
    $url = str_replace($search, $replace, $url);

    //replace common characters
    $search = array('&', '£', '$'); 
    $replace = array('and', 'pounds', 'dollars'); 
    $url= str_replace($search, $replace, $url);

    // remove - for spaces and union characters
    $find = array(' ', '&', '\r\n', '\n', '+', ',', '//');
    $url = str_replace($find, '-', $url);

    //delete and replace rest of special chars
    $find = array('/[^a-z0-9\-<>]/', '/[\-]+/', '/<[^>]*>/');
    $replace = array('', '-', '');
    $uri = preg_replace($find, $replace, $url);

    return $uri;
}
John Magnolia
sumber
5

dan ini adalah versi Joomla 3.3.2 JFile::makeSafe($file)

public static function makeSafe($file)
{
    // Remove any trailing dots, as those aren't ever valid file names.
    $file = rtrim($file, '.');

    $regex = array('#(\.){2,}#', '#[^A-Za-z0-9\.\_\- ]#', '#^\.#');

    return trim(preg_replace($regex, '', $file));
}
cedric.walter
sumber
4

Menurut saya memiliki daftar karakter untuk dihapus tidak aman. Saya lebih suka menggunakan yang berikut ini:

Untuk nama file: Gunakan ID internal atau hash dari konten file. Simpan nama dokumen dalam database. Dengan cara ini Anda dapat menyimpan nama file asli dan tetap menemukan file tersebut.

Untuk parameter url: Gunakan urlencode()untuk menyandikan karakter khusus apa pun.

ZeissS
sumber
1
Saya setuju, sebagian besar metode yang tercantum di sini menghapus karakter berbahaya yang diketahui - metode saya menghapus semua yang bukan karakter aman yang diketahui . Karena sebagian besar sistem slug menyandikan URL posting, saya sarankan agar kami terus mengikuti metode yang telah terbukti ini daripada menggunakan yang didokumentasikan urlencode () yang tidak aman UTF-8 yang .
Xeoncross
3

Bergantung pada bagaimana Anda akan menggunakannya, Anda mungkin ingin menambahkan batas panjang untuk melindungi dari buffer overflows.

Tgr
sumber
Ya, pengujian untuk mb_strlen () selalu merupakan hal yang penting!
Xeoncross
3

Ini adalah cara yang bagus untuk mengamankan nama file unggahan:

$file_name = trim(basename(stripslashes($name)), ".\x00..\x20");
permainan
sumber
Saya tidak begitu yakin tentang ini, karena seseorang .\x00..\x20dapat direduksi menjadi .\x00\x20.
Xeoncross
@ Xeoncross: Saya pikir itu .\x00..\x20menghapus titik-titik dan setiap karakter antara \x00dan \x20, sedangkan .\x00\x20seharusnya hanya menghapus 3 byte tersebut.
Alix Axel
Jawaban ini membutuhkan lebih banyak penjelasan agar dapat digunakan dengan aman. Tidak banyak informasi tentang sintaks yang tepat untuk daftar karakter di internet.
Manuel Arwed Schmidt
3

Berikut implementasi CodeIgniter.

/**
 * Sanitize Filename
 *
 * @param   string  $str        Input file name
 * @param   bool    $relative_path  Whether to preserve paths
 * @return  string
 */
public function sanitize_filename($str, $relative_path = FALSE)
{
    $bad = array(
        '../', '<!--', '-->', '<', '>',
        "'", '"', '&', '$', '#',
        '{', '}', '[', ']', '=',
        ';', '?', '%20', '%22',
        '%3c',      // <
        '%253c',    // <
        '%3e',      // >
        '%0e',      // >
        '%28',      // (
        '%29',      // )
        '%2528',    // (
        '%26',      // &
        '%24',      // $
        '%3f',      // ?
        '%3b',      // ;
        '%3d'       // =
    );

    if ( ! $relative_path)
    {
        $bad[] = './';
        $bad[] = '/';
    }

    $str = remove_invisible_characters($str, FALSE);
    return stripslashes(str_replace($bad, '', $str));
}

Dan remove_invisible_charactersketergantungan.

function remove_invisible_characters($str, $url_encoded = TRUE)
{
    $non_displayables = array();

    // every control character except newline (dec 10),
    // carriage return (dec 13) and horizontal tab (dec 09)
    if ($url_encoded)
    {
        $non_displayables[] = '/%0[0-8bcef]/';  // url encoded 00-08, 11, 12, 14, 15
        $non_displayables[] = '/%1[0-9a-f]/';   // url encoded 16-31
    }

    $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S';   // 00-08, 11, 12, 14-31, 127

    do
    {
        $str = preg_replace($non_displayables, '', $str, -1, $count);
    }
    while ($count);

    return $str;
}
Kevin Mark
sumber
2

mengapa tidak menggunakan php saja urlencode? itu menggantikan karakter "berbahaya" dengan representasi hex mereka untuk url (yaitu %20untuk spasi)

rajutan
sumber
2
Karakter% tidak direkomendasikan untuk nama file dan karakter yang dikodekan hex tidak terlihat bagus di URL. Browser dapat mendukung string UTF-8 yang jauh lebih bagus dan lebih mudah untuk bahasa non-ascii.
Xeoncross
Anda bisa melakukan urlencode dan KEMUDIAN str_replace ('% 20', '-', url)?
Francesco
2

Sudah ada beberapa solusi yang disediakan untuk pertanyaan ini tetapi saya telah membaca dan menguji sebagian besar kode di sini dan saya berakhir dengan solusi ini yang merupakan campuran dari apa yang saya pelajari di sini:

Fungsinya

Fungsi ini dibundel di sini dalam bundel Symfony2 tetapi dapat diekstrak untuk digunakan sebagai PHP biasa , itu hanya memiliki ketergantungan denganiconv fungsi yang harus diaktifkan:

Filesystem.php :

<?php

namespace COil\Bundle\COilCoreBundle\Component\HttpKernel\Util;

use Symfony\Component\HttpKernel\Util\Filesystem as BaseFilesystem;

/**
 * Extends the Symfony filesystem object.
 */
class Filesystem extends BaseFilesystem
{
    /**
     * Make a filename safe to use in any function. (Accents, spaces, special chars...)
     * The iconv function must be activated.
     *
     * @param string  $fileName       The filename to sanitize (with or without extension)
     * @param string  $defaultIfEmpty The default string returned for a non valid filename (only special chars or separators)
     * @param string  $separator      The default separator
     * @param boolean $lowerCase      Tells if the string must converted to lower case
     *
     * @author COil <https://github.com/COil>
     * @see    http://stackoverflow.com/questions/2668854/sanitizing-strings-to-make-them-url-and-filename-safe
     *
     * @return string
     */
    public function sanitizeFilename($fileName, $defaultIfEmpty = 'default', $separator = '_', $lowerCase = true)
    {
    // Gather file informations and store its extension
    $fileInfos = pathinfo($fileName);
    $fileExt   = array_key_exists('extension', $fileInfos) ? '.'. strtolower($fileInfos['extension']) : '';

    // Removes accents
    $fileName = @iconv('UTF-8', 'us-ascii//TRANSLIT', $fileInfos['filename']);

    // Removes all characters that are not separators, letters, numbers, dots or whitespaces
    $fileName = preg_replace("/[^ a-zA-Z". preg_quote($separator). "\d\.\s]/", '', $lowerCase ? strtolower($fileName) : $fileName);

    // Replaces all successive separators into a single one
    $fileName = preg_replace('!['. preg_quote($separator).'\s]+!u', $separator, $fileName);

    // Trim beginning and ending seperators
    $fileName = trim($fileName, $separator);

    // If empty use the default string
    if (empty($fileName)) {
        $fileName = $defaultIfEmpty;
    }

    return $fileName. $fileExt;
    }
}

Tes unit

Yang menarik adalah saya telah membuat tes PHPUnit, pertama untuk menguji kasus edge dan Anda dapat memeriksa apakah itu sesuai dengan kebutuhan Anda: (Jika Anda menemukan bug, silakan tambahkan kasus uji)

FilesystemTest.php :

<?php

namespace COil\Bundle\COilCoreBundle\Tests\Unit\Helper;

use COil\Bundle\COilCoreBundle\Component\HttpKernel\Util\Filesystem;

/**
 * Test the Filesystem custom class.
 */
class FilesystemTest extends \PHPUnit_Framework_TestCase
{
    /**
     * test sanitizeFilename()
     */
    public function testFilesystem()
    {
    $fs = new Filesystem();

    $this->assertEquals('logo_orange.gif', $fs->sanitizeFilename('--logö  _  __   ___   ora@@ñ--~gé--.gif'), '::sanitizeFilename() handles complex filename with specials chars');
    $this->assertEquals('coilstack', $fs->sanitizeFilename('cOiLsTaCk'), '::sanitizeFilename() converts all characters to lower case');
    $this->assertEquals('cOiLsTaCk', $fs->sanitizeFilename('cOiLsTaCk', 'default', '_', false), '::sanitizeFilename() lower case can be desactivated, passing false as the 4th argument');
    $this->assertEquals('coil_stack', $fs->sanitizeFilename('coil stack'), '::sanitizeFilename() convert a white space to a separator');
    $this->assertEquals('coil-stack', $fs->sanitizeFilename('coil stack', 'default', '-'), '::sanitizeFilename() can use a different separator as the 3rd argument');
    $this->assertEquals('coil_stack', $fs->sanitizeFilename('coil          stack'), '::sanitizeFilename() removes successive white spaces to a single separator');
    $this->assertEquals('coil_stack', $fs->sanitizeFilename('       coil stack'), '::sanitizeFilename() removes spaces at the beginning of the string');
    $this->assertEquals('coil_stack', $fs->sanitizeFilename('coil   stack         '), '::sanitizeFilename() removes spaces at the end of the string');
    $this->assertEquals('coilstack', $fs->sanitizeFilename('coil,,,,,,stack'), '::sanitizeFilename() removes non-ASCII characters');
    $this->assertEquals('coil_stack', $fs->sanitizeFilename('coil_stack  '), '::sanitizeFilename() keeps separators');
    $this->assertEquals('coil_stack', $fs->sanitizeFilename(' coil________stack'), '::sanitizeFilename() converts successive separators into a single one');
    $this->assertEquals('coil_stack.gif', $fs->sanitizeFilename('cOil Stack.GiF'), '::sanitizeFilename() lower case filename and extension');
    $this->assertEquals('copy_of_coil.stack.exe', $fs->sanitizeFilename('Copy of coil.stack.exe'), '::sanitizeFilename() keeps dots before the extension');
    $this->assertEquals('default.doc', $fs->sanitizeFilename('____________.doc'), '::sanitizeFilename() returns a default file name if filename only contains special chars');
    $this->assertEquals('default.docx', $fs->sanitizeFilename('     ___ -  --_     __%%%%__¨¨¨***____      .docx'), '::sanitizeFilename() returns a default file name if filename only contains special chars');
    $this->assertEquals('logo_edition_1314352521.jpg', $fs->sanitizeFilename('logo_edition_1314352521.jpg'), '::sanitizeFilename() returns the filename untouched if it does not need to be modified');
    $userId = rand(1, 10);
    $this->assertEquals('user_doc_'. $userId. '.doc', $fs->sanitizeFilename('亐亐亐亐亐.doc', 'user_doc_'. $userId), '::sanitizeFilename() returns the default string (the 2nd argument) if it can\'t be sanitized');
    }
}

Hasil pengujian: (diperiksa di Ubuntu dengan PHP 5.3.2 dan MacOsX dengan PHP 5.3.17:

All tests pass:

phpunit -c app/ src/COil/Bundle/COilCoreBundle/Tests/Unit/Helper/FilesystemTest.php
PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /var/www/strangebuzz.com/app/phpunit.xml.dist

.

Time: 0 seconds, Memory: 5.75Mb

OK (1 test, 17 assertions)
Gulungan
sumber
1
Ini mengasumsikan sebagian besar masukan berbasis Latin. Tambahkan lebih banyak karakter UTF-8 dari bahasa lain untuk melihat di mana Anda akan mendapat masalah.
Xeoncross
@Xeoncross Saya setuju, karena Christian berkata seseorang harus menyimpan Id atau hash DAN nama file asli. Tetapi fungsi ini menyediakan alternatif karena Anda dapat menentukan string default ketika proses pembersihan gagal. Saya telah menambahkan tes unit untuk kasus ini. Terima kasih telah melaporkan bug tersebut.
COil
2

Saya memiliki judul entri dengan semua jenis karakter latin yang aneh serta beberapa tag HTML yang perlu saya terjemahkan ke dalam format nama file yang dipisahkan tanda hubung. Saya menggabungkan jawaban @ SoLoGHoST dengan beberapa item dari jawaban @ Xeoncross dan menyesuaikan sedikit.

    function sanitize($string,$force_lowercase=true) {
    //Clean up titles for filenames
    $clean = strip_tags($string);
    $clean = strtr($clean, array('Š' => 'S','Ž' => 'Z','š' => 's','ž' => 'z','Ÿ' => 'Y','À' => 'A','Á' => 'A','Â' => 'A','Ã' => 'A','Ä' => 'A','Å' => 'A','Ç' => 'C','È' => 'E','É' => 'E','Ê' => 'E','Ë' => 'E','Ì' => 'I','Í' => 'I','Î' => 'I','Ï' => 'I','Ñ' => 'N','Ò' => 'O','Ó' => 'O','Ô' => 'O','Õ' => 'O','Ö' => 'O','Ø' => 'O','Ù' => 'U','Ú' => 'U','Û' => 'U','Ü' => 'U','Ý' => 'Y','à' => 'a','á' => 'a','â' => 'a','ã' => 'a','ä' => 'a','å' => 'a','ç' => 'c','è' => 'e','é' => 'e','ê' => 'e','ë' => 'e','ì' => 'i','í' => 'i','î' => 'i','ï' => 'i','ñ' => 'n','ò' => 'o','ó' => 'o','ô' => 'o','õ' => 'o','ö' => 'o','ø' => 'o','ù' => 'u','ú' => 'u','û' => 'u','ü' => 'u','ý' => 'y','ÿ' => 'y'));
    $clean = strtr($clean, array('Þ' => 'TH', 'þ' => 'th', 'Ð' => 'DH', 'ð' => 'dh', 'ß' => 'ss', 'Œ' => 'OE', 'œ' => 'oe', 'Æ' => 'AE', 'æ' => 'ae', 'µ' => 'u','—' => '-'));
    $clean = str_replace("--", "-", preg_replace("/[^a-z0-9-]/i", "", preg_replace(array('/\s/', '/[^\w-\.\-]/'), array('-', ''), $clean)));

    return ($force_lowercase) ?
        (function_exists('mb_strtolower')) ?
            mb_strtolower($clean, 'UTF-8') :
            strtolower($clean) :
        $clean;
}

Saya perlu menambahkan karakter em dash (-) ke array terjemahan secara manual. Mungkin ada yang lain, tetapi sejauh ini nama file saya terlihat bagus.

Begitu:

Bagian 1: "Žurburts" ayahku? - mereka (bukan) yang terbaik!

menjadi:

bagian-1-ayah-saya-zurburts-mereka-bukan-yang-terbaik

Saya hanya menambahkan ".html" ke string yang dikembalikan.

cbmtrx.dll
sumber
1
Masih kehilangan beberapa karakter Ceko dan Slowakia:'ľ' => 'l', 'Ľ' => 'L', 'č' => 'c', 'Č' => 'C', 'ť' => 't', 'Ť' => 'T', 'ň' => 'n', 'Ň' => 'N', 'ĺ' => 'l', 'Ĺ' => 'L', 'Ř' => 'R', 'ř' => 'r', 'ě' => 'e', 'Ě' => 'E', 'ů' => 'u', 'Ů' => 'U'
Jasom Dotnet
1
Dan tidak diragukan lagi banyak lagi. Saya sebenarnya mencoba mencari tahu apakah ada set ISO yang menyertakan kombinasi karakter. Bagaimana seseorang "memilih" satu set jika konten menuntut karakter dari semuanya? UTF-8 Saya berasumsi ...
cbmtrx
Saya menemukan cara mentransliterasi string apa pun menggunakan satu baris PHP : $string = transliterator_transliterate('Any-Latin;Latin-ASCII;', $string);Lihat jawaban saya di bawah ini atau baca posting blog yang ditautkan.
Jasom Dotnet
1
Tidak, Anda salah membacanya: JIKA Anda dapat menginstal ekstensi PHP di server (atau hosting) Anda :-) Ini dia kirimannya .
Jasom Dotnet
1
Ah, mengerti. Terima kasih @JasomDotnet --Solusi saya saat ini berfungsi untuk saat ini tetapi ini adalah rangkaian karakter terbatas sehingga ekstensi ini layak untuk dicoba.
cbmtrx
2

Solusi # 1: Anda memiliki kemampuan untuk menginstal ekstensi PHP di server (hosting)

Untuk transliterasi dari "hampir setiap bahasa di planet Bumi" ke karakter ASCII.

  1. Instal ekstensi PHP Intl terlebih dahulu. Ini adalah perintah untuk Debian (Ubuntu):sudo aptitude install php5-intl

  2. Ini adalah fungsi nama file saya (buat test.php dan tempelkan kode berikut di sana):

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test</title>
</head>
<body>
<?php

function pr($string) {
  print '<hr>';
  print '"' . fileName($string) . '"';
  print '<br>';
  print '"' . $string . '"';
}

function fileName($string) {
  // remove html tags
  $clean = strip_tags($string);
  // transliterate
  $clean = transliterator_transliterate('Any-Latin;Latin-ASCII;', $clean);
  // remove non-number and non-letter characters
  $clean = str_replace('--', '-', preg_replace('/[^a-z0-9-\_]/i', '', preg_replace(array(
    '/\s/', 
    '/[^\w-\.\-]/'
  ), array(
    '_', 
    ''
  ), $clean)));
  // replace '-' for '_'
  $clean = strtr($clean, array(
    '-' => '_'
  ));
  // remove double '__'
  $positionInString = stripos($clean, '__');
  while ($positionInString !== false) {
    $clean = str_replace('__', '_', $clean);
    $positionInString = stripos($clean, '__');
  }
  // remove '_' from the end and beginning of the string
  $clean = rtrim(ltrim($clean, '_'), '_');
  // lowercase the string
  return strtolower($clean);
}
pr('_replace(\'~&([a-z]{1,2})(ac134/56f4315981743 8765475[]lt7ňl2ú5äňú138yé73ťž7ýľute|');
pr(htmlspecialchars('<script>alert(\'hacked\')</script>'));
pr('Álix----_Ãxel!?!?');
pr('áéíóúÁÉÍÓÚ');
pr('üÿÄËÏÖÜ.ŸåÅ');
pr('nie4č a a§ôňäääaš');
pr('Мао Цзэдун');
pr('毛泽东');
pr('ماو تسي تونغ');
pr('مائو تسه‌تونگ');
pr('מאו דזה-דונג');
pr('მაო ძედუნი');
pr('Mao Trạch Đông');
pr('毛澤東');
pr('เหมา เจ๋อตง');
?>
</body>
</html>

Baris ini adalah inti:

  // transliterate
  $clean = transliterator_transliterate('Any-Latin;Latin-ASCII;', $clean);

Jawaban berdasarkan posting ini .

Solusi # 2: Anda tidak memiliki kemampuan untuk menginstal ekstensi PHP di server (hosting)

masukkan deskripsi gambar di sini

Pekerjaan yang cukup bagus dilakukan dalam modul transliterasi untuk CMS Drupal. Ini mendukung hampir setiap bahasa di planet Bumi. Saya sarankan untuk memeriksa repositori plugin jika Anda ingin memiliki solusi yang benar-benar lengkap membersihkan string.

Jasom Dotnet
sumber
1

Ini adalah fungsi yang bagus:

public function getFriendlyURL($string) {
    setlocale(LC_CTYPE, 'en_US.UTF8');
    $string = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $string);
    $string = preg_replace('~[^\-\pL\pN\s]+~u', '-', $string);
    $string = str_replace(' ', '-', $string);
    $string = trim($string, "-");
    $string = strtolower($string);
    return $string;
} 
joan16v
sumber
Ini terlihat buruk. \\s+berarti garis miring terbalik diikuti dengan satu atau lebih spasi. Tentang apa itu? Selain itu, ini menggunakan daftar hitam daripada memasukkan daftar putih mengabaikan hal-hal seperti CMD, null, atau BEL.
Xeoncross
Masih buruk. Sekarang string seperti /blog/2014-02/just-in-timetidak diperbolehkan. Silakan gunakan kode yang diuji di atas atau gunakan phunctionkode kerangka PHP.
Xeoncross
Betul sekali. Fungsi ini hanya untuk bagian "just-in-time". Bisa bermanfaat bagi sebagian orang.
joan16v
1
Anda dapat mengubah regexpreg_replace('~[^\-\pL\pN\s]+~u', '-', $string)
Xeoncross
Hebat! Saya juga menambahkan: string = trim ($ string, "-");
joan16v
0

Ini adalah kode yang digunakan oleh PrestaShop untuk membersihkan url:

replaceAccentedChars

digunakan oleh

str2url

untuk menghilangkan diakritik

function replaceAccentedChars($str)
{
    $patterns = array(
        /* Lowercase */
        '/[\x{0105}\x{00E0}\x{00E1}\x{00E2}\x{00E3}\x{00E4}\x{00E5}]/u',
        '/[\x{00E7}\x{010D}\x{0107}]/u',
        '/[\x{010F}]/u',
        '/[\x{00E8}\x{00E9}\x{00EA}\x{00EB}\x{011B}\x{0119}]/u',
        '/[\x{00EC}\x{00ED}\x{00EE}\x{00EF}]/u',
        '/[\x{0142}\x{013E}\x{013A}]/u',
        '/[\x{00F1}\x{0148}]/u',
        '/[\x{00F2}\x{00F3}\x{00F4}\x{00F5}\x{00F6}\x{00F8}]/u',
        '/[\x{0159}\x{0155}]/u',
        '/[\x{015B}\x{0161}]/u',
        '/[\x{00DF}]/u',
        '/[\x{0165}]/u',
        '/[\x{00F9}\x{00FA}\x{00FB}\x{00FC}\x{016F}]/u',
        '/[\x{00FD}\x{00FF}]/u',
        '/[\x{017C}\x{017A}\x{017E}]/u',
        '/[\x{00E6}]/u',
        '/[\x{0153}]/u',

        /* Uppercase */
        '/[\x{0104}\x{00C0}\x{00C1}\x{00C2}\x{00C3}\x{00C4}\x{00C5}]/u',
        '/[\x{00C7}\x{010C}\x{0106}]/u',
        '/[\x{010E}]/u',
        '/[\x{00C8}\x{00C9}\x{00CA}\x{00CB}\x{011A}\x{0118}]/u',
        '/[\x{0141}\x{013D}\x{0139}]/u',
        '/[\x{00D1}\x{0147}]/u',
        '/[\x{00D3}]/u',
        '/[\x{0158}\x{0154}]/u',
        '/[\x{015A}\x{0160}]/u',
        '/[\x{0164}]/u',
        '/[\x{00D9}\x{00DA}\x{00DB}\x{00DC}\x{016E}]/u',
        '/[\x{017B}\x{0179}\x{017D}]/u',
        '/[\x{00C6}]/u',
        '/[\x{0152}]/u');

    $replacements = array(
            'a', 'c', 'd', 'e', 'i', 'l', 'n', 'o', 'r', 's', 'ss', 't', 'u', 'y', 'z', 'ae', 'oe',
            'A', 'C', 'D', 'E', 'L', 'N', 'O', 'R', 'S', 'T', 'U', 'Z', 'AE', 'OE'
        );

    return preg_replace($patterns, $replacements, $str);
}

function str2url($str)
{
    if (function_exists('mb_strtolower'))
        $str = mb_strtolower($str, 'utf-8');

    $str = trim($str);
    if (!function_exists('mb_strtolower'))
        $str = replaceAccentedChars($str);

    // Remove all non-whitelist chars.
    $str = preg_replace('/[^a-zA-Z0-9\s\'\:\/\[\]-\pL]/u', '', $str);
    $str = preg_replace('/[\s\'\:\/\[\]-]+/', ' ', $str);
    $str = str_replace(array(' ', '/'), '-', $str);

    // If it was not possible to lowercase the string with mb_strtolower, we do it after the transformations.
    // This way we lose fewer special chars.
    if (!function_exists('mb_strtolower'))
        $str = strtolower($str);

    return $str;
}
Armel Larcier
sumber
-4
// CLEAN ILLEGAL CHARACTERS
function clean_filename($source_file)
{
    $search[] = " ";
    $search[] = "&";
    $search[] = "$";
    $search[] = ",";
    $search[] = "!";
    $search[] = "@";
    $search[] = "#";
    $search[] = "^";
    $search[] = "(";
    $search[] = ")";
    $search[] = "+";
    $search[] = "=";
    $search[] = "[";
    $search[] = "]";

    $replace[] = "_";
    $replace[] = "and";
    $replace[] = "S";
    $replace[] = "_";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";

    return str_replace($search,$replace,$source_file);

} 
Brant Messenger
sumber