Comment vérifier si une URL est valide

94

Comment puis-je vérifier si une chaîne est une URL valide?

Par exemple:

http://hello.it => yes
http:||bra.ziz, => no

S'il s'agit d'une URL valide, comment puis-je vérifier si elle est relative à un fichier image?

Luca Romagnoli
la source
l'url que vous avez fournie semble être une URL absolue, que voulez-vous dire par rapport à un fichier image
johannes

Réponses:

178

Utilisez le URImodule distribué avec Ruby:

require 'uri'

if url =~ URI::regexp
    # Correct URL
end

Comme Alexander Günther l'a dit dans les commentaires, il vérifie si une chaîne contient une URL.

Pour vérifier si la chaîne est une URL, utilisez:

url =~ /\A#{URI::regexp}\z/

Si vous souhaitez uniquement vérifier les URL Web ( httpou https), utilisez ceci:

url =~ /\A#{URI::regexp(['http', 'https'])}\z/
Mikael S
la source
25
Cela ne semble pas fonctionner: 'http://:5984/asdf' =~ URI::regexpet les 'http::5984/asdf' =~ URI::regexpdeux renvoient 0. Je m'attendais à ce qu'ils renvoient nil car aucun d'entre eux n'est un URI valide.
awendt
4
N'est-ce pas: 5984 port 5984 sur localhost?
mxcl
3
Il vérifie en fait si une variable contient une URL valide. Il acceptera " example com" comme URL valide. Parce qu'il en contient un. Mais ce n'est pas utile si vous vous attendez à ce que tout soit l'URL.
Alexander Günther
2
gotqn: Ce n'est pas une URL valide selon la RFC 1738.
Mikael S
12
Ne l'utilisez pas, c'est tellement mauvais que "http:"cette expression rationnelle passe.
smathy
43

Semblable aux réponses ci-dessus, je trouve que l'utilisation de cette expression régulière est légèrement plus précise:

URI::DEFAULT_PARSER.regexp[:ABS_URI]

Cela invalidera les URL avec des espaces, par opposition à URI.regexpce qui autorise les espaces pour une raison quelconque.

J'ai récemment trouvé un raccourci fourni pour les différents rgexps URI. Vous pouvez accéder URI::DEFAULT_PARSER.regexp.keysdirectement à partir de URI::#{key}.

Par exemple, l' :ABS_URIexpression rationnelle est accessible depuis URI::ABS_URI.

jonuts
la source
3
Si vous prévoyez d'utiliser URI.parse à tout moment, c'est certainement la voie à suivre. URI :: regexp correspond à certaines URL qui échoueront lors de l'utilisation ultérieure de URI.parse. Merci pour le conseil.
markquezada
Malheureusement, cela n'est disponible que sur Ruby 1.9, et non sur 1.8.
Steve Madsen
1
Mais, cela fonctionne: /^#{URI.regexp}$/. Le problème est que URI.regexpcela ne s'ancre pas. Une chaîne avec un espace ne valide pas l'espace en tant que partie de l'URI, mais tout ce qui mène à l'espace. Si ce fragment ressemble à un URI valide, la correspondance réussit.
Steve Madsen
3
Appliquer le commentaire de awendt à vos propositions: 'http://:5984/asdf' =~ URI::DEFAULT_PARSER.regexp[:ABS_URI]donne 0, pas nul; 'http::5984/asdf'=~ URI::DEFAULT_PARSER.regexp[:ABS_URI]donne 0; 'http://:5984/asdf' =~ /^#{URI.regexp}$/donne 0; 'http::5984/asdf' =~ /^#{URI.regexp}$/donne également 0. Aucune des expressions rationnelles ci-dessus n'est entièrement correcte, mais elles échouent uniquement dans des situations très très étranges et ce n'est pas un gros problème dans la plupart des cas.
skalee
1
FYI, URI::DEFAULT_PARSER.regexp[:ABS_URI]est identique à/\A\s*#{URI::regexp}\s*\z/
aidan
36

Le problème avec les réponses actuelles est qu'un URI n'est pas une URL .

Un URI peut être davantage classé en tant que localisateur, nom ou les deux. Le terme «Uniform Resource Locator» (URL) fait référence au sous-ensemble d'URI qui, en plus d'identifier une ressource, fournissent un moyen de localiser la ressource en décrivant son mécanisme d'accès principal (par exemple, son «emplacement» réseau).

Étant donné que les URL sont un sous-ensemble d'URI, il est clair que la correspondance spécifiquement pour les URI correspondra avec succès aux valeurs indésirables. Par exemple, les URN :

 "urn:isbn:0451450523" =~ URI::regexp
 => 0 

Cela étant dit, pour autant que je sache, Ruby n'a pas de méthode par défaut pour analyser les URL, vous aurez donc probablement besoin d'une gemme pour le faire. Si vous avez besoin de faire correspondre des URL spécifiquement au format HTTP ou HTTPS, vous pouvez faire quelque chose comme ceci:

uri = URI.parse(my_possible_url)
if uri.kind_of?(URI::HTTP) or uri.kind_of?(URI::HTTPS)
  # do your stuff
end
fotanus
la source
@Philip était à la fois utile et approprié. Merci beaucoup!
fotanus
2
uri.kind_of?(URI::HTTP)semble être suffisant pour les deux cas (http et https), du moins dans ruby ​​1.9.3.
Andrea Salicetti
souffre toujours des problèmes décrits par @skalee sous la réponse de
jonuts
1
Résumé, URI.parse(string_to_be_checked).kind_of?(URI::HTTP)fait bien le travail.
ben
De plus, une erreur de frappe très courante dans notre base de données montre que les gens ont tendance à mettre de nombreuses barres obliques:, http:///neopets.comce qui est malheureusement également valide. Vérifier la présence d'un nom d'hôte corrige ceci:uri = URI(str) ; %w[http https].include?(uri.scheme) && !uri.host.nil?
Shane il y a
19

Je préfère le joyau adressable . J'ai trouvé qu'il gère les URL de manière plus intelligente.

require 'addressable/uri'

SCHEMES = %w(http https)

def valid_url?(url)
  parsed = Addressable::URI.parse(url) or return false
  SCHEMES.include?(parsed.scheme)
rescue Addressable::URI::InvalidURIError
  false
end
David J.
la source
3
J'ai juste alimenté Addressable :: URI.parse () avec les chaînes les plus étranges pour voir ce qu'il rejette. Il a accepté des trucs dingues. Cependant, la première chaîne qu'il n'a pas acceptée était ":-)". Hmm.
mvw
1
Comment cela suscite-t-il autant de votes positifs? Addressable::URI.parsene renvoie pas nil avec une entrée invalide.
garbagecollector
11

C'est une entrée assez ancienne, mais j'ai pensé que j'irais de l'avant et contribuerais:

String.class_eval do
    def is_valid_url?
        uri = URI.parse self
        uri.kind_of? URI::HTTP
    rescue URI::InvalidURIError
        false
    end
end

Vous pouvez maintenant faire quelque chose comme:

if "http://www.omg.wtf".is_valid_url?
    p "huzzah!"
end
Wilhelm Murdoch
la source
2
Cela fonctionne beaucoup mieux que les solutions ci-dessus. Il ne contient pas les mises en garde énumérées ci-dessus et n'accepte pas non plus les URL telles que javascript: alert ('spam').
bchurchill
2
mais il correspond également http:/, ce qui n'est peut-être pas ce que vous voulez.
Bo Jeanes
10

Pour moi, j'utilise cette expression régulière:

/^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix

Option:

  • i - insensible à la casse
  • x - ignorer les espaces dans les regex

Vous pouvez définir cette méthode pour vérifier la validation d'URL:

def valid_url?(url)
  url_regexp = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
  url =~ url_regexp ? true : false
end

Pour l'utiliser:

valid_url?("http://stackoverflow.com/questions/1805761/check-if-url-is-valid-ruby")

Test avec de mauvaises URL:

  • http://ruby3arabi - le résultat est invalide
  • http://http://ruby3arabi.com - le résultat est invalide
  • http:// - le résultat est invalide

Testez avec les URL correctes:

  • http://ruby3arabi.com - le résultat est valide
  • http://www.ruby3arabi.com - le résultat est valide
  • https://www.ruby3arabi.com - le résultat est valide
  • https://www.ruby3arabi.com/article/1 - le résultat est valide
  • https://www.ruby3arabi.com/websites/58e212ff6d275e4bf9000000?locale=en - le résultat est valide
Komsun K.
la source
Ce qui suit est marqué comme valide:, "http://test.com\n<script src=\"nasty.js\">"et tout domaine qui utilise l'un des 683 TLD de plus de 5 caractères, ou a deux traits d'union consécutifs ou plus, est marqué comme invalide. Les numéros de port en dehors de la plage 0-65535 sont autorisés. Les adresses FTP et IP sont évidemment interdites, mais il convient de le noter.
aidan
1
facilement la meilleure solution la plus applicable ici pour une vérification rapide des URL. merci
somedirection
4

C'est un peu vieux mais voici comment je le fais. Utilisez le module URI de Ruby pour analyser l'URL. Si elle peut être analysée, c'est une URL valide. (Mais cela ne veut pas dire accessible.)

L'URI prend en charge de nombreux schémas, et vous pouvez ajouter vous-même des schémas personnalisés:

irb> uri = URI.parse "http://hello.it" rescue nil
=> #<URI::HTTP:0x10755c50 URL:http://hello.it>

irb> uri.instance_values
=> {"fragment"=>nil,
 "registry"=>nil,
 "scheme"=>"http",
 "query"=>nil,
 "port"=>80,
 "path"=>"",
 "host"=>"hello.it",
 "password"=>nil,
 "user"=>nil,
 "opaque"=>nil}

irb> uri = URI.parse "http:||bra.ziz" rescue nil
=> nil


irb> uri = URI.parse "ssh://hello.it:5888" rescue nil
=> #<URI::Generic:0x105fe938 URL:ssh://hello.it:5888>
[26] pry(main)> uri.instance_values
=> {"fragment"=>nil,
 "registry"=>nil,
 "scheme"=>"ssh",
 "query"=>nil,
 "port"=>5888,
 "path"=>"",
 "host"=>"hello.it",
 "password"=>nil,
 "user"=>nil,
 "opaque"=>nil}

Consultez la documentation pour plus d'informations sur le module URI.

nyzm
la source
J'ai rencontré ceci en essayant de réparer un segfault. L'utilisation en URI.parseétait en fait la cause dans Ruby 2.5.5 - Je suis passé à la réponse @jonuts ci-dessous si cela ne vous dérange pas que certains cas étranges échouent. Pour mes besoins, je m'en fichais donc c'était idéal.
el n00b le
3

En général,

/^#{URI::regexp}$/

fonctionnera bien, mais si vous ne voulez correspondre qu'à httpou https, vous pouvez les transmettre en tant qu'options à la méthode:

/^#{URI::regexp(%w(http https))}$/

Cela a tendance à fonctionner un peu mieux si vous souhaitez rejeter des protocoles comme ftp://.

user2275806
la source
-2

Vous pouvez également utiliser une expression régulière, peut-être quelque chose comme http://www.geekzilla.co.uk/View2D3B0109-C1B2-4B4E-BFFD-E8088CBC85FD.htm en supposant que cette expression régulière est correcte (je ne l'ai pas complètement vérifié), ce qui suit sera montrer la validité de l'url.

url_regex = Regexp.new("((https?|ftp|file):((//)|(\\\\))+[\w\d:\#@%/;$()~_?\+-=\\\\.&]*)")

urls = [
    "http://hello.it",
    "http:||bra.ziz"
]

urls.each { |url|
    if url =~ url_regex then
        puts "%s is valid" % url
    else
        puts "%s not valid" % url
    end
}

L'exemple ci-dessus génère:

http://hello.it is valid
http:||bra.ziz not valid
Jamie
la source
5
Qu'en est-il du schéma mailto? Ou telnet, gopher, nntp, rsync, ssh ou l'un des autres schémas? Les URL sont un peu plus compliquées que simplement HTTP et FTP.
mu est trop court
Écrire une expression régulière pour valider les URL est difficile. Pourquoi s'embêter?
Rimian
@Rimian, vous devez vous embêter car tout ce que vous URIpouvez faire est en fait cassé. Voir les commentaires sous les nombreuses réponses positives ci-dessus. Je ne sais pas si la réponse de Janie est juste, mais j'espère que les gens la considéreront plus sérieusement. TBH Je finis par faire url.start_with?("http://") || url.start_with?("https://")parce que je n'ai besoin que de HTTP et que les utilisateurs devraient être responsables d'utiliser les URL appropriées.
akostadinov