filtros - php sanitize html code
sanitizer de cadena para nombre de archivo (16)
$ fname = str_replace (''/'', '''', $ fname);
Dado que los usuarios pueden usar la barra para separar dos palabras, sería mejor reemplazarla por una línea en lugar de NULL
Estoy buscando una función php que desinfecte una cadena y la prepare para un nombre de archivo. Alguien sabe de una práctica?
(Podría escribir uno, ¡pero me preocupa que pase por alto a un personaje!)
Editar: para guardar archivos en un sistema de archivos Windows NTFS.
¿Qué pasa con el uso de rawurlencode ()? http://www.php.net/manual/en/function.rawurlencode.php
Aquí hay una función que desinfecta incluso caracteres chinos:
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;
}
Aquí está la explicación
- Eliminar etiquetas HTML
- Retire las pausas / lengüetas / transporte de retorno
- Eliminar caracteres ilegales para la carpeta y el nombre de archivo
- Pon la cuerda en minúsculas
- Elimina acentos extranjeros como Éàû convirtiéndolo en entidades html y luego elimina el código y guarda la carta.
- Reemplazar espacios con guiones
- Codifique los caracteres especiales que podrían pasar los pasos anteriores e ingrese el nombre de archivo del conflicto en el servidor. ex. "中文 百强 网"
- Reemplace "%" con guiones para asegurarse de que el enlace del archivo no será reescrito por el navegador al consultar el archivo.
OK, algún nombre de archivo no será reverso, pero en la mayoría de los casos funcionará.
ex. Nombre original: "საბეჭდი-და-jpg"
Nombre de salida: "-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 "
Es mejor así que un error 404.
Espero que haya sido útil.
Carl.
Así es como se puede desinfectar para un sistema de archivos como se lo pidió
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;
}
Todo lo demás está permitido en un sistema de archivos, por lo que la pregunta está perfectamente respondida ...
... pero podría ser peligroso permitir, por ejemplo, comillas simples ''
en un nombre de archivo si lo usa más adelante en un contexto HTML inseguro porque:
NotExist'' onerror=''alert(1).jpg
se convierte en un agujero XSS :
<img src=''<? echo $image ?>'' />
// output:
<img src=''NotExist'' onerror=''alert(1)'' />
Debido a eso, el popular software de CMS, Wordpress elimina y aprendieron year tras year por el camino difícil (muchos informes de errores), que es útil agregar más y más caracteres:
$special_chars = array("?", "[", "]", "/", "//", "=", "<", ">", ":", ";", ",", "''", "/"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", "%", "+", chr(0));
// ... a few rows later are whitespaces removed as well ...
preg_replace( ''/[/r/n/t -]+/'', ''-'', $filename )
Finalmente, su lista incluye ahora la mayoría de los caracteres que forman parte de la lista de caracteres reutilizados de URI y de caracteres inseguros de URL .
Por supuesto, podría simplemente codificar todos estos caracteres en la salida de HTML, pero la mayoría de los desarrolladores y yo también, seguimos el modismo "Mejor prevenir que lamentar" y eliminarlos por adelantado.
Así que finalmente sugeriría usar esto:
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);
// maximise 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;
}
Todo lo demás que no causa problemas con el sistema de archivos debe ser parte de una función adicional:
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;
}
Y en este punto debe generar un nombre de archivo si el resultado está vacío y puede decidir si desea codificar caracteres UTF-8. Pero no es necesario, ya que UTF-8 está permitido en todos los sistemas de archivos que se utilizan en contextos de alojamiento web.
Lo único que tienes que hacer es usar urlencode()
(como esperemos que lo hagas con todas tus URL) para que el nombre de archivo საბეჭდი_მანქანა.jpg
convierta en esta URL como tu <img src>
o <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
hace eso, así que puedo publicar este enlace como lo haría un usuario:
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
Así que este es un nombre de archivo legal completo y no es un problema como lo mencionó @ SequenceDigitale.com en su respuesta .
Bueno, tempnam () lo hará por ti.
http://us2.php.net/manual/en/function.tempnam.php
pero eso crea un nombre completamente nuevo.
Para desinfectar una cadena existente solo restrinja lo que pueden ingresar sus usuarios y haga que letras, números, punto, guión y guión bajo lo desinfecte con una expresión regular simple. Compruebe qué personajes necesitan escaparse o puede obtener falsos positivos.
$sanitized = preg_replace(''/[^a-zA-Z0-9/-/._]/'','''', $filename);
Estos pueden ser un poco pesados, pero son lo suficientemente flexibles como para desinfectar cualquier cadena en un nombre de archivo o nombre de carpeta estilo "seguro" (o diablos, incluso babosos y cosas depuradas si lo dobla).
1) Crear un nombre de archivo completo (con el nombre alternativo en caso de que la entrada esté truncada por completo):
str_file($raw_string, $word_separator, $file_extension, $fallback_name, $length);
2) O usando solo el filtro util sin construir un nombre de archivo completo (el modo estricto true
no permitirá [] o () en el nombre del archivo):
str_file_filter($string, $separator, $strict, $length);
3) Y estas son esas funciones:
// 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(" ", '' '', $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;
}
}
Entonces, digamos que la entrada de algunos usuarios es: .....<div></div><script></script>& Weiß Göbel 中文百强网File name %20 %20 %21 %2C Décor //. /. . z /... y /...... x ./ “This name” is & 462^^ not = that grrrreat -][09]()1234747) საბეჭდი-და-ტიპოგრაფიული
.....<div></div><script></script>& Weiß Göbel 中文百强网File name %20 %20 %21 %2C Décor //. /. . z /... y /...... x ./ “This name” is & 462^^ not = that grrrreat -][09]()1234747) საბეჭდი-და-ტიპოგრაფიული
Y queremos convertirlo en algo más amigable para crear un tar.gz con una longitud de 255 caracteres. Aquí hay un uso de ejemplo. Nota: este ejemplo incluye una extensión tar.gz malformada como prueba de concepto, aún debe filtrar la extensión después de que la cadena se construya contra su (s) lista (s) blanca (s).
$raw_str = ''.....<div></div><script></script>& Weiß Göbel 中文百强网File name %20 %20 %21 %2C Décor //. /. . z /... y /...... x ./ “This name” is & 462^^ not = 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);
El resultado sería: _wei_gbel_file_name_dcor_._._._z_._y_._x_._this_name_is_462_not_that_grrrreat_][09]()1234747)_.tar.gz
Puedes jugar aquí: https://3v4l.org/iSgi8
O una Gist: https://gist.github.com/dhaupin/b109d3a8464239b7754a
EDIT: filtro de script actualizado para
en lugar de espacio, enlace 3v4l actualizado
Haciendo un pequeño ajuste a la solución de Sean Vieira para permitir un solo punto, puede usar:
preg_replace("([^/w/s/d/./-_~,;:/[/]/(/)]|[/.]{2,})", '''', $file)
Haciendo un pequeño ajuste a la solución de Tor Valamo para solucionar el problema observado por Dominic Rodger, podría usar:
// 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);
La siguiente expresión crea una cadena agradable, limpia y utilizable:
/[^a-z0-9/._-]+/gi
Convirtiendo lo financiero de hoy: la facturación en la facturación financiera de hoy
Lo mejor que sé hoy es el método estático Strings::webalize del framework Nette.
Por cierto, esto traduce todos los signos diacríticos a sus básicos ... š => s ü => u ß => ss etc.
Para los nombres de archivo, debe agregar el punto "." para el parámetro de caracteres permitidos.
/**
* 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;
}
PHP proporciona una función para desinfectar un texto a un formato diferente
Cómo :
echo filter_var(
"Lorem Ipsum has been the industry''s",FILTER_SANITIZE_URL
);
Blockquote
LoremIpsumhasbeentheindustry''s
Parece que todo depende de la pregunta: ¿es posible crear un nombre de archivo que pueda usarse para piratear un servidor (o hacer algún otro daño)? Si no es así, parece que la respuesta simple es intentar crear el archivo donde quiera que sea, finalmente, ser utilizado (ya que ese será el sistema operativo de elección, sin duda). Deje que el sistema operativo lo resuelva. Si se queja, transfiera esa queja al Usuario como un Error de Validación.
Esto tiene el beneficio adicional de ser confiablemente portátil, ya que todos los sistemas operativos (estoy bastante seguro) se quejarán si el nombre del archivo no está formado correctamente para ese sistema operativo.
Si es posible hacer cosas infames con un nombre de archivo, tal vez haya medidas que se puedan aplicar antes de probar el nombre de archivo en el sistema operativo residente: medidas menos complicadas que una "limpieza" completa del nombre del archivo.
de una sola mano
$bad=''/[//:*?"<>|]/'';
$string = ''fi?le*'';
function sanitize($str,$pat)
{
return preg_replace($pat,"",$str);
}
echo sanitize($string,$bad);
/
y ..
en el nombre de archivo proporcionado por el usuario puede ser dañino. Entonces debería deshacerse de estos por algo como:
$fname = str_replace(''..'', '''', $fname);
$fname = str_replace(''/'', '''', $fname);
SOLUCIÓN 1 : simple y efectiva
$file_name = preg_replace( ''/[^a-z0-9]+/'', ''-'', strtolower( $url ) );
- strtolower () garantiza que el nombre del archivo esté en minúscula (ya que el asunto no importa dentro de la URL, sino en el nombre de archivo NTFS)
-
[^a-z0-9]+
se asegurará de que el nombre de archivo solo contenga letras y números - Sustituir caracteres inválidos con
''-''
mantiene el nombre de archivo legible
Ejemplo:
URL: http://.com/questions/2021624/string-sanitizer-for-filename
File: http--com-questions-2021624-string-sanitizer-for-filename
SOLUCIÓN 2 : para URL muy largas
Desea almacenar en caché los contenidos de la URL y solo necesita tener nombres de archivo únicos. Yo usaría esta función:
$file_name = md5( strtolower( $url ) )
esto creará un nombre de archivo con longitud fija. El hash MD5 es en la mayoría de los casos lo suficientemente único para este tipo de uso.
Ejemplo:
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
En lugar de preocuparte por los personajes que pasan por alto, ¿qué tal si utilizas una lista blanca de personajes que te alegra que utilices? Por ejemplo, podría permitir simplemente buenos ol '' az
, 0-9
, _
, y una sola instancia de un punto ( .
). Eso es obviamente más limitante que la mayoría de los sistemas de archivos, pero debería mantenerte a salvo.
preg_replace("[^/w/s/d/./-_~,;:/[/]/(/]]", '''', $file)
Agregue / elimine más caracteres válidos según lo que esté permitido para su sistema.
Alternativamente, puede intentar crear el archivo y luego devolver un error si es malo.