regex to match a URL with optional 'www' and protocol - php

I'm trying to write a regexp.
some background info: I am try to see if the REQUEST_URI of my website's URL contains another URL. like these:
http://mywebsite.com/google.com/search=xyz
However, the url wont always contain the 'http' or the 'www'. so the pattern should also match strings like:
http://mywebsite.com/yahoo.org/search=xyz
http://mywebsite.com/www.yahoo.org/search=xyz
http://mywebsite.com/msn.co.uk'
http://mywebsite.com/http://msn.co.uk'
there are a bunch of regexps out there to match urls but none I have found do an optional match on the http and www.
i'm wondering if the pattern to match could be something like:
^([a-z]).(com|ca|org|etc)(.)
I thought maybe another option was to perhaps just match any string that had a dot (.) in it. (as the other REQUEST_URI's in my application typically won't contain dots)
Does this make sense to anyone?
I'd really appreciate some help with this its been blocking my project for weeks.
Thanks you very much
-Tim

I suggest using a simple approach, essentially building on what you said, just anything with a dot in it, but working with the forward slashes too. To capture everything and not miss unusual URLs. So something like:
^((?:https?:\/\/)?[^./]+(?:\.[^./]+)+(?:\/.*)?)$
It reads as:
optional http:// or https://
non-dot-or-forward-slash characters
one or more sets of a dot followed by non-dot-or-forward-slash characters
optional forward slash and anything after it
Capturing the whole thing to the first grouping.
It would match, for example:
nic.uk
nic.uk/
http://nic.uk
http://nic.uk/
https://example.com/test/?a=bcd
Verifying they are valid URLs is another story! It would also match:
index.php
It would not match:
directory/index.php
The minimal match is basically something.something, with no forward slash in it, unless it comes at least one character past the dot. So just be sure not to use that format for anything else.

To match an optional part, you use a question mark ?, see Optional Items.
For example to match an optional www., capture the domain and the search term, the regular expression could be
(www\.)?(.+?)/search=(.+)
Although, the question mark in .+? is a non-greedy quantifier, see http://www.regular-expressions.info/repeat.html.

You might try starting your regex with
^(http://)?(www\.)?
And then the rules to match the rest of a URL.

$re = '/http:\/\/mywebsite\.com\/((?:http:\/\/)?[0-9A-Za-z]+(?:-+[0-9A-Za-z]+)*(?:\.[0-9A-Za-z]+(?:-+[0-9A-Za-z]+)*)+(?:\/.*)?)/';
https://regex101.com/r/x6vUvp/1
Obeys the DNS rule that hyphens must be surrounded. Replace http with https? to allow https URLs as well.
According to the list of TLDs at Wikipedia there are at least 1519 of them and it's not constant so you may want to give the domain its own capture group so it can be verified with an online API or a file listing them all.

Here is my two cents :
$regex = "/http:\/\/mywebsite\.com\/((http:\/\/|www\.)?[a-z]*(\.org|\.co\.uk|\.com).*)/";
See the working exemple
But I'm sure you can do better !
Hope it helps.

Related

Regex for detecting a word enclosed but in order

I have a regex that needs to match up a specific url and load some configuration based on that.
Basically What I am have is /*[^(search)].php/ This regex needs to match every url that has .php in the end but parameters may be present (something.pgp?t=19) except for the urls that have search.php
For example
1. http://www.example.com/discuss/viewtopic.php?t=19
2. http://www.example.com/discuss/viewforum.php?f=8
3. http://www.example.com/discuss/search.php?f=8
Among the above three urls the regular expression needs to be able to match 1 & 2 but not 3.
Any help is much appreciated thanks.
EDITED
However it should not be matching any other urls that does not include .php in it.
www.example.com/something should not be matched.
try this:
/.+?(?<!search)\.php(?<params>.*)/
the key is the non-greedy 'anything' .+? : it crawls up the string one by one, always checking for "look behind you and don't see 'search', followed by .php: (?<!search)\.php, followed by the named group which are the optional query string params.
Note that this simple regex is pretty permissive, and assumes that .php alone signifies a "php URL" - you could get crazy complicated validating URL's.
Just use two different location (make sure search.php is before general *.php)
location ~ /search\.php$ {
# config for phusion-passenger
}
location ~ \.php$ {
# config for php-fpm
}
Nginx strip off request parameters while searching for match, so you don't have to care about them.
Problem in /*[^(search)].php/
[^ ] negates of character class
so [^(search)] here would match anything other than ( or s or e or a etc
Solution
You can use a look behind assertion as
^.*(?<!search\.php)\?([^=]=)+\d+$
will match 1 and 2
Example : http://regex101.com/r/bJ3vG1/4
What it doess?
(?<!search\.php) negative lookbehind. asserts that the regex is presceded not by search.php
\?[^=]=\d+ matches parameters
Edit
If the parameter part is optional, a lengthier regex would do the purpose
.*(?<!search\.php)\?([^=]=)+\d+$|^[^?]*(?<!search\.php)$
Example : http://regex101.com/r/bJ3vG1/3

How to remove backpath/parentpath from the URL?

Input:
http://foo/bar/baz/../../qux/
Desired Output:
http://foo/qux/
This can be achieved using regular expression (unless someone can suggest a more efficient alternative).
If it was a forward look-up, it would be as simple as:
/\.\.\/[^\/]+/
Though I am not familiar with with how to make a backward look up for the first "/" (ie. not doing /[a-z0-9-_]+\/\.\./).
One of the solutions I thought of is to use strrev then apply forward look up regex (first example) and then do strrev. Though I am sure there is a more efficient way.
Not the clearest question I've ever seen, but if I understand what you're asking, I think you only need to switch around what you have like this:
/[^\/]+/\.\./
...then replace that with a /
Do that until no replacements are made and you should have what you want
EDIT
Your attempt seems to try to match a forward slash / and two dots \.\. followed by a slash / (or \/ - they should both match the same thing), then one or more non-slash characters[^/]+, terminated by a slash /. Flipping it around, you want to find a slash followed by one or more non-slash characters and a terminating slash, then two dots and a final slash.
You may be confused into thinking that the regex engine parses and consumes things as it goes (so you wouldn't want to consume a directory name that is not followed by the correct number of dots), but that's not how it typically works - a regex engine matches the entire expression before it replaces or returns anything. So, you can have two dots followed by a directory name, or a directory name followed by two dots - it doesn't make a difference to the engine.
If your attempt is using the slash-enclosed Perl-style syntax, then you would of course need to use \/ for any slashes you're trying to match such as the middle one, but I would also recommend matching and replacing the enclosing slashes in the url as well: I think the PHP would be something like
preg_replace('/\/[^\/]+\/\.\.\//', '/', $input)
(??)
Technically what do you want is replace segments of '/path1/path2/../../' by '/' what is needed to do that is match 'pathx/'^n'../'^n that is definetly NOT a regular expression (Context Free Lenguaje) ... but most of Regex libraries supports some non regular lenguajes and can (with a lot of effort) manage those kind of lenguajes.
An easy way to solve it is stay in Regular Expressions and cycle several times, replacing '/[^./]+/../' by ''
if you still to do it in a single step, Lookahead and grouping is needed, but it will be hard to write it, (I'm not so used on, but I will try)
EDIT:
I've found the solution in only 1 REGEX... but should use PCRE Regex
([^/.]+/(?1)?\.\./)
I've based my solution on the folowing link:
Match a^n b^n c^n (e.g. "aaabbbccc") using regular expressions (PCRE)
(note that dots are "forbidden" in the first section, you cannot have path.1/path.2/ if you whant to is quite more complex because you should admit them but forbid '../' as valid in the first section
this sub expression is for admiting the path names like 'path1/'
[^/.]+/
this sub expression is for admiting the double dots.
\.\./
you can test the regexp in
https://www.debuggex.com/
(remember to set it in PCRE mode)
Here is a working copy:
https://eval.in/52675

URL routing regex

I'm trying to create a snippet of regex that will match a URL route.
Basically, if I have this route /users/:id I want /users/100 to match, but /users/100/edit not to match.
This is what I'm using now: users/(.*)/ but because of the greedy match it's matching regardless of what's after the user ID. I need some way of "breaking" the match if there's an /edit or something else on the end of the route.
I've looked into the Regex NOT operator but with no luck.
Any advice?
Are you just trying to collect digits?
You could use users/(\d*)/
And this one is how you would do it if you wanted to collect everything until a /, and it uses a NOT, ^/users/[^/]*$
You can use negative lookahead:
users/(.*)/(?!edit)
This will always require a trailing slash however. Maybe a better solution would be:
users/(\d+)(?!/edit)
See this post for more information.

Why doesn't this URL pattern match?

I'm using a pattern as described by John Gruber in this daringfireball article to auto link URLs in user comments.
I'm using it with PHP to match URLs, and want it to match a single TLD with no www and no trailing slash, but it doesn't seem to be working.
Here's the pattern (and can be seen in more detail at the article above):
$pattern = '#(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4})(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))#';
Specifically I'm looking at this particular subpattern: [a-z0-9.\-]+[.][a-z]{2,4}
This subpattern works separately, but as a part of the larger pattern, it doesn't match google.com.
[a-z0-9.\-]+[.][a-z]{2,4} works as you expect, but the rest of the pattern requires at least 1 following character:
google.com/
google.com?lang=en-us
google.com#!foo/bar
etc.
You can try allowing the tail to be optional, but it may in turn give you false-positives rather than excluding false-negatives:
$pattern = '#...“”‘’])?)#'; # '...' for brevity
# ^
Works for me:
http://regexr.com?2uica
Are you sure there is nothing in you php that is tripping you up?
EDIT
It's because the full pattern expects to find something before the domain name, like http:// or www

help with a regex code

i have this regex code
/^(https?:\/\/+[\w\-]+\.[\w\-]+)/i
it works but there is a problem
you NEED http:// in the url for it to validate, and what i am making, the user will not want to add http:// to the url they want to just have example.com, if its possible i need it to work weather it has http:// or not
i don't know how to make my own regex, and ive searched but cannot find a one that does what i need, unless im just not looking in the right place. (Google :P)
Don't bother with regex. Use parse_url function.
You can just make it optional
/^((?:https?:\/\/+)?[\w\-]+\.[\w\-]+)/i
The (?:) around the part you don't want to have is a non capturing group, the ? afterwards makes it optional.
I'm not sure what the + after the second slash is good for, it says at least one of the preceding character. That means it allows also stuff like http://////////.
I hope you are aware, that this regex is far from matching valid URLs.
For example it will match stuff like
http://////////------------.-
or at least
http://N.O
^ after this position you can write what you want and it will match valid.
Here on Regexr you can see what your regex is matching.
See Purple Coder's answer for a probably better solution.
/^((https?:\/\/+)?[\w-]+.[\w-]+)/i
I'm using this :
// Validate that the string contains at least a dot .
var filterWebsite = /^([a-zA-Z0-9:_\.\-/])+\.([a-zA-Z0-9_\.\-/])+$/;

Categories