Estou tentando criar uma função que faz um bom trabalho na limpeza de certas seqüências de caracteres para que elas sejam seguras para uso na URL (como uma publicação pós-lesma) e também para uso como nomes de arquivo. Por exemplo, quando alguém faz o upload de um arquivo, desejo remover todos os caracteres perigosos do nome.
Até agora, criei a seguinte função, que espero resolver esse problema e permita também dados UTF-8 estrangeiros.
/**
* 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');
}
Alguém tem dados de amostra complicados que eu possa executar contra isso - ou conhece uma maneira melhor de proteger nossos aplicativos de nomes ruins?
$ is-filename permite alguns caracteres adicionais, como arquivos temporários do vim
update: removeu o caractere estrela, pois não conseguia pensar em um uso válido
fonte
Respostas:
Algumas observações sobre sua solução:
Criando a lesma
Você provavelmente não deve incluir caracteres acentuados etc. na sua publicação, pois, tecnicamente, eles devem ser codificados em porcentagem (de acordo com as regras de codificação de URL), para que você tenha URLs feios.
Então, se eu fosse você, depois de usar letras minúsculas, converteria qualquer caractere 'especial' para seu equivalente (por exemplo, é -> e) e substituiria caracteres não [az] por '-', limitando a execução de um único '-' como você fez. Há uma implementação de conversão de caracteres especiais aqui: https://web.archive.org/web/20130208144021/http://neo22s.com/slug
Sanitização em geral
O OWASP possui uma implementação em PHP de sua API de Segurança Corporativa que, entre outras coisas, inclui métodos para codificação e decodificação seguras de entrada e saída em seu aplicativo.
A interface do codificador fornece:
https://github.com/OWASP/PHP-ESAPI https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API
fonte
สังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่.txt
e, em seguida, criei um arquivo HTML UTF-8 com um link para ele. Surpreendentemente, funcionou - mesmo nas janelas! No entanto, eu tinha o PHPfile_put_contents('สังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่.txt')
e ele falhou ao criar um nome de arquivo de bazar a partir dessa string. Então tentei criá-lofopen()
e obtive o mesmo nome de arquivo bagunçado. Então, aparentemente, o PHP (pelo menos no Windows) é incapaz de criar nomes de arquivos UTF-8. bugs.php.net/bug.php?id=46990&thanks=6Eu encontrei essa função maior no código Chyrp :
e este no código wordpress
Atualização de setembro de 2012
Alix Axel fez um trabalho incrível nesta área. Sua estrutura de funções inclui vários ótimos filtros e transformações de texto.
fonte
apply_filters
/[\s-]+/
com-
o que é melhor do que a primeira versão (que substitui apenas/\s+/
) que pode causar vários traços em uma linhaIsso deve tornar seus nomes de arquivos seguros ...
e uma solução mais profunda para isso é:
Isso pressupõe que você deseja um ponto no nome do arquivo. se você quiser transferi-lo para minúsculas, use
para a última linha.
fonte
'ľ' => 'l', 'Ľ' => 'L', 'č' => 'c', 'Č' => 'C', 'ť' => 't', 'Ť' => 'T', 'ň' => 'n', 'Ň' => 'N', 'ĺ' => 'l', 'Ĺ' => 'L', 'Ř' => 'R', 'ř' => 'r', 'ě' => 'e', 'Ě' => 'E', 'ů' => 'u', 'Ů' => 'U'
Tente o seguinte:
Com base na resposta selecionada neste tópico: Nome de usuário amigável do URL em PHP?
fonte
trim()
também deve sertrim($string, '-')
.preg_replace()
deve remover todos os caracteres perigosos.Esta não é exatamente uma resposta, pois ainda não fornece nenhuma solução, mas é grande demais para caber em um comentário ...
Fiz alguns testes (sobre nomes de arquivos) no Windows 7 e Ubuntu 12.04 e o que descobri foi:
1. O PHP não pode manipular nomes de arquivos não ASCII
Embora o Windows e o Ubuntu possam lidar com nomes de arquivos Unicode (mesmo os de RTL, ao que parece), o PHP 5.3 exige que os hacks lidem mesmo com a antiga ISO-8859-1, por isso é melhor mantê-lo ASCII apenas por segurança.
2. O comprimento dos assuntos de nome de arquivo (especialmente no Windows)
No Ubuntu, o tamanho máximo que um nome de arquivo pode ter (incluindo a extensão) é 255 (excluindo caminho):
No entanto, no Windows 7 (NTFS), o comprimento máximo que um nome de arquivo pode ter depende de seu caminho absoluto:
A Wikipedia diz que:
Que eu saiba (e teste), isso está errado.
No total (contando barras), todos esses exemplos têm 259 caracteres, se você remover o
C:\
que fornece 256 caracteres (não 255 ?!). Os diretórios foram criados usando o Explorer e você notará que ele se impede de usar todo o espaço disponível para o nome do diretório. O motivo disso é permitir a criação de arquivos usando a convenção de nomenclatura 8.3 . O mesmo acontece com outras partições.Os arquivos não precisam reservar os requisitos de 8,3 comprimentos, é claro:
Você não pode criar mais subdiretórios se o caminho absoluto do diretório pai tiver mais de 242 caracteres, porque
256 = 242 + 1 + \ + 8 + . + 3
. Usando o Windows Explorer, você não pode criar outro diretório se o diretório pai tiver mais de 233 caracteres (dependendo da localidade do sistema), porque256 = 233 + 10 + \ + 8 + . + 3
; o10
aqui é o comprimento da stringNew folder
.O sistema de arquivos do Windows apresenta um problema desagradável se você deseja garantir a interoperabilidade entre os sistemas de arquivos.
3. Cuidado com caracteres reservados e palavras-chave
Além de remover caracteres não ASCII, imprimíveis e de controle , você também precisa re (colocar / mover):
Apenas remover esses caracteres pode não ser a melhor ideia, pois o nome do arquivo pode perder parte do seu significado. Eu acho que, no mínimo, várias ocorrências desses caracteres devem ser substituídas por um único sublinhado (
_
), ou talvez algo mais representativo (isso é apenas uma ideia):"*?
->_
/\|
->-
:
->[ ]-[ ]
<
->(
>
->)
Também há palavras-chave especiais que devem ser evitadas (como
NUL
), embora eu não tenha certeza de como superar isso. Talvez uma lista negra com um nome aleatório substituto seja uma boa abordagem para resolvê-lo.4. Sensibilidade ao Caso
Isso deve ser óbvio, mas se você quiser garantir a exclusividade dos arquivos em diferentes sistemas operacionais, deverá transformar os nomes dos arquivos em um caso normalizado, dessa forma,
my_file.txt
eMy_File.txt
no Linux, os dois não se tornarão o mesmomy_file.txt
arquivo no Windows.5. Certifique-se de que é único
Se o nome do arquivo já existir, um identificador exclusivo deve ser anexado ao seu nome de arquivo base.
Identificadores exclusivos comuns incluem o registro de data e hora do UNIX, um resumo do conteúdo do arquivo ou uma sequência aleatória.
6. Arquivos ocultos
Só porque pode ser nomeado não significa que deveria ...
Os pontos são geralmente listados em nomes de arquivos, mas no Linux, um arquivo oculto é representado por um ponto inicial.
7. Outras considerações
Se você precisar remover alguns caracteres do nome do arquivo, a extensão geralmente é mais importante que o nome base do arquivo. Permitindo um número máximo considerável de caracteres para a extensão do arquivo (8-16), deve-se retirar os caracteres do nome base. Também é importante observar que, no caso improvável de ter mais de uma extensão longa - como
_.graphmlz.tag.gz
-_.graphmlz.tag
apenas_
deve ser considerado como o nome base do arquivo nesse caso.8. Recursos
O Calibre lida com o nome de arquivo que é confuso:
Página da Wikipedia sobre o nome do arquivo desconectado e o capítulo vinculado do Using Samba .
Se, por exemplo, você tentar criar um arquivo que viole alguma das regras 1/2/3, receberá um erro muito útil:
fonte
Eu sempre achei que Kohana fez um bom trabalho nisso .
O prático
UTF8::transliterate_to_ascii()
transformará coisas como ñ => n.Obviamente, você pode substituir os outros
UTF8::*
itens por funções mb_ *.fonte
Em termos de upload de arquivos, você seria mais seguro para impedir que o usuário controle o nome do arquivo. Como já foi sugerido, armazene o nome do arquivo canônico em um banco de dados, juntamente com um nome escolhido aleatoriamente e exclusivo que você usará como o nome do arquivo real.
Usando OWASP ESAPI, esses nomes podem ser gerados assim:
Você pode anexar um carimbo de data / hora ao $ safeFilename para ajudar a garantir que o nome do arquivo gerado aleatoriamente seja exclusivo, sem mesmo procurar um arquivo existente.
Em termos de codificação para URL e novamente usando ESAPI:
Esse método executa a canonização antes de codificar a sequência e manipula todas as codificações de caracteres.
fonte
Eu recomendo * URLify para PHP (mais de 480 estrelas no Github) - "a porta PHP de URLify.js do projeto Django. Translitera caracteres não-ascii para uso em URLs".
Uso básico:
Para gerar slugs para URLs:
Para gerar slugs para nomes de arquivos:
* Nenhuma das outras sugestões corresponde aos meus critérios:
Como bônus, o URLify também remove certas palavras e retira todos os caracteres não transliterados.
Aqui está um caso de teste com toneladas de caracteres estrangeiros sendo transliterados corretamente usando URLify: https://gist.github.com/motin/a65e6c1cc303e46900d10894bf2da87f
fonte
Eu me adaptei de outra fonte e adicionei mais alguns, talvez um pouco de exagero
fonte
e esta é a versão Joomla 3.3.2 da
JFile::makeSafe($file)
fonte
Eu não acho que ter uma lista de caracteres para remover seja seguro. Prefiro usar o seguinte:
Para nomes de arquivos: use um ID interno ou um hash do conteúdo do arquivo. Salve o nome do documento em um banco de dados. Dessa forma, você pode manter o nome do arquivo original e ainda encontrar o arquivo.
Para parâmetros de URL: use
urlencode()
para codificar qualquer caractere especial.fonte
Dependendo de como você o usará, convém adicionar um limite de comprimento para proteger contra estouros de buffer.
fonte
Esta é uma boa maneira de proteger um nome de arquivo de upload:
fonte
.\x00..\x20
pode ser reduzido a.\x00\x20
..\x00..\x20
remove pontos e todos os caracteres entre\x00
e\x20
, considerando que.\x00\x20
deve remover apenas esses 3 bytes.Aqui está a implementação do CodeIgniter.
E a
remove_invisible_characters
dependência.fonte
por que não simplesmente usar php's
urlencode
? ele substitui caracteres "perigosos" por sua representação hexadecimal por URLs (ou seja,%20
por um espaço)fonte
Já existem várias soluções fornecidas para esta pergunta, mas li e testei a maior parte do código aqui e acabei com essa solução, que é uma mistura do que aprendi aqui:
A função
A função é empacotada aqui em um pacote Symfony2, mas pode ser extraída para ser usada como PHP simples ; ela possui apenas uma dependência da
iconv
função que deve ser ativada:Filesystem.php :
Os testes de unidade
O interessante é que eu criei testes PHPUnit, primeiro para testar casos extremos e, assim, você pode verificar se ele atende às suas necessidades: (Se você encontrar um bug, sinta-se à vontade para adicionar um caso de teste)
FilesystemTest.php :
Os resultados do teste: (verificado no Ubuntu com PHP 5.3.2 e MacOsX com PHP 5.3.17:
fonte
Tenho títulos de entrada com todos os tipos de caracteres latinos estranhos, bem como algumas tags HTML que eu precisava para traduzir em um formato de nome de arquivo útil, delimitado por traços. Combinei a resposta do @ SoLoGHoST com alguns itens da resposta do @ Xeoncross e personalizei um pouco.
Eu precisava adicionar manualmente o caractere traço em (-) à matriz de tradução. Pode haver outros, mas até agora meus nomes de arquivos estão com boa aparência.
Assim:
Parte 1: Os Žurburts do meu pai? - eles (não) são os melhores!
torna-se:
parte-1-meus-pais-zurburts-eles não são os melhores
Acabei de adicionar ".html" à string retornada.
fonte
'ľ' => 'l', 'Ľ' => 'L', 'č' => 'c', 'Č' => 'C', 'ť' => 't', 'Ť' => 'T', 'ň' => 'n', 'Ň' => 'N', 'ĺ' => 'l', 'Ĺ' => 'L', 'Ř' => 'R', 'ř' => 'r', 'ě' => 'e', 'Ě' => 'E', 'ů' => 'u', 'Ů' => 'U'
$string = transliterator_transliterate('Any-Latin;Latin-ASCII;', $string);
Veja minha resposta abaixo ou leia a postagem do blog vinculada.Solução 1: você pode instalar extensões PHP no servidor (hospedagem)
Para transliteração de "quase todas as línguas do planeta Terra" para caracteres ASCII.
Instale a extensão PHP Intl primeiro. Este é um comando para o Debian (Ubuntu):
sudo aptitude install php5-intl
Esta é a minha função fileName (crie test.php e cole o seguinte código):
Esta linha é essencial:
Resposta baseada nesta postagem .
Solução 2: você não tem capacidade para instalar extensões PHP no servidor (hospedagem)
Um bom trabalho é feito no módulo de transliteração do CMS Drupal. Ele suporta quase todas as línguas do planeta Terra. Sugiro verificar o repositório de plug-ins se você quiser ter realmente soluções completas para higienizar a solução.
fonte
Este post parece funcionar melhor entre tudo o que amarrei. http://gsynuh.com/php-string-filename-url-safe/205
fonte
Esta é uma boa função:
fonte
\\s+
significa uma barra invertida seguida por um ou mais espaços em branco. O que é isso? Além disso, isso usa a lista negra em vez da lista de permissões, ignorando coisas comoCMD
, null ouBEL
./blog/2014-02/just-in-time
não são permitidas. Por favor, use o código testado acima ou use ophunction
código da estrutura PHP.preg_replace('~[^\-\pL\pN\s]+~u', '-', $string)
Este é o código usado pelo Prestashop para limpar os URLs:
é usado por
remover diacríticos
fonte
Existem 2 boas respostas para armazenar seus dados, use-os https://stackoverflow.com/a/3987966/971619 ou https://stackoverflow.com/a/7610586/971619
fonte
fonte