55

I need to verify an image url to check whether the url is an image of any of these extensions:- jpeg, jpg, gif, png. Example:- when we verify this url http://www.example.com/asdf.jpg it should give us true value and with url like this http://www.example.com/asdf.php should return false. How can we do this in javascript and also i want to check the content type of url. So that we can say whether the url is an image or not.

John Preston
  • 765
  • 3
  • 8
  • 11
  • 1
    So you want to verify if a url **in a string** ends with the right extension? Then you also want to read the content of the image? – gideon Mar 15 '12 at 05:38
  • 1
    @gideon yes i want a string with right extension but i'am not sure if this is ok or not and that's why i want to check the content type of the url – John Preston Mar 15 '12 at 05:40
  • 1
    Does this question contain 3 parts, verify it is a valid url? verify it is a image extension? verify the content of the image? – louis.luo Mar 15 '12 at 05:41
  • 1
    what if the url doesn't tell us the file type? How can we distinguish in that case? – Urasquirrel Sep 24 '21 at 17:00

7 Answers7

138

You can use a regular expression like this to check the file extension:

function checkURL(url) {
    return(url.match(/\.(jpeg|jpg|gif|png)$/) != null);
}

This checks to see if the url ends in any of those four extensions.

I know of no way from javascript in the client to verify the content-type of a URL that isn't on the same domain as the web page because you can't use ajax outside of the domain of the web page. As best I know, you'd have to ship the URL to a server process and have it download the image, get the content type and return that to you.

But, you can check to see if an image tag can load the URL by using a function like this:

function testImage(url, callback, timeout) {
    timeout = timeout || 5000;
    var timedOut = false, timer;
    var img = new Image();
    img.onerror = img.onabort = function() {
        if (!timedOut) {
            clearTimeout(timer);
            callback(url, "error");
        }
    };
    img.onload = function() {
        if (!timedOut) {
            clearTimeout(timer);
            callback(url, "success");
        }
    };
    img.src = url;
    timer = setTimeout(function() {
        timedOut = true;
        // reset .src to invalid URL so it stops previous
        // loading, but doesn't trigger new load
        img.src = "//!!!!/test.jpg";
        callback(url, "timeout");
    }, timeout); 
}

This function will call your callback at some future time with two arguments: the original URL and a result ("success", "error" or "timeout"). You can see this work on several URLs, some good and some bad, here: http://jsfiddle.net/jfriend00/qKtra/


And, since this is now the era of Promises, here's a version that returns a promise:

function testImage(url, timeoutT) {
    return new Promise(function (resolve, reject) {
        var timeout = timeoutT || 5000;
        var timer, img = new Image();
        img.onerror = img.onabort = function () {
            clearTimeout(timer);
            reject("error");
        };
        img.onload = function () {
            clearTimeout(timer);
            resolve("success");
        };
        timer = setTimeout(function () {
            // reset .src to invalid URL so it stops previous
            // loading, but doesn't trigger new load
            img.src = "//!!!!/test.jpg";
            reject("timeout");
        }, timeout);
        img.src = url;
    });
}

And, a jsFiddle demo: http://jsfiddle.net/jfriend00/vhtzghkd/

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • thanks for your help. This function works but how can we check the content-type of the url. I mean the first step is to check the extension of the url and i want to make it more secure by adding second step to check the content type of url. – John Preston Mar 15 '12 at 06:41
  • ok so how about if the person enters the url of a php file like this http://www.example.com/asdf.php.jpg then how can we return false value to that because our function is going to return true. – John Preston Mar 15 '12 at 06:45
  • @JohnPreston - I've added two ways you can test the URL to my answer. One, you ship the URL off to a server and have it test the content-type. Two, you can run some code to load it into an image tag and see if that succeeds. – jfriend00 Mar 15 '12 at 07:05
  • Thankssssss alot man. You're AWESOME. You save my time. It works. Thanks again for your support and time. – John Preston Mar 15 '12 at 07:08
  • For those looking for quick usage `testImage(inputUrl, function(url, result) {if (result === 'success') {console.log(url)}}, 10000);` – Sorter Mar 11 '14 at 12:21
  • Thanks for the answer ... I am little new to regex --In this expression `/\.(jpeg|jpg|gif|png)$/` what is $ for ? – Hitesh Sep 10 '14 at 16:40
  • @hitesh - If you're new to regex, you'll want a [good reference like this](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) that lists all the special characters. The `$` matches the end of the string so that forces the regex to match the file extension only at the end of the url. – jfriend00 Sep 10 '14 at 16:44
  • be careful, if the image has a query at the end like image.jpg?something, this would fail, even though nothing is wrong with the image url. – Nick Feb 08 '16 at 12:24
  • @OmidHezaveh - The regex can be changed to `/\.(jpeg|jpg|gif|png)($|\?)/` if you want to allow a query string. – jfriend00 Feb 08 '16 at 16:59
  • Added a promise version to my answer. – jfriend00 Aug 21 '16 at 01:00
  • Since you're here, can you explain the need for the timeout? So far, I've just used what you wrote without it, directly replacing the xmlhttprequest I'd previously used (which didn't work since I would sometimes get invalid images from the host). – trlkly Aug 21 '16 at 23:06
  • @trlkly - The timeout is a failsafe against a connection that gets stuck in DNS lookup or downloading and doesn't fail or succeed in a reasonable amount of time. Other than a few lines of code, it doesn't cost anything and asserts control over operations that don't complete in the desired time. – jfriend00 Aug 22 '16 at 22:27
  • Encountered an issue. If the page hasn't finished loading, then the page never stops loading if the image times out. I had to add to the timeout function `img.src = '';` to get the loading to stop. (I know that can send an additional request in some browsers, but nothing else worked. window.stop() might stop the loading before the rest of the page loads.) – trlkly Aug 26 '16 at 02:41
  • @trlkly - What browser does that? I added that to the code in my answer. – jfriend00 Aug 26 '16 at 03:03
  • Happens in both Chrome(ium) and Firefox. It's not that easy to test--you have to inject the code while the page is loading. And you need a URL that will always timeout (I used `http://google.com:80` from another Question). If you meant which browser sends another request, that's from another Answer that links https://www.nczonline.net/blog/2009/11/30/empty-image-src-can-destroy-your-site/. Chrome has since fixed the bug, but I don't know about IE. – trlkly Aug 27 '16 at 03:12
  • @trlkly - I've just never seen a browser that includes Javascript loaded images in the page loading UI. That seems like a bug. – jfriend00 Aug 27 '16 at 03:18
  • Make that http://google.com:81. It just never returns. And, yeah, I'd think that you would not want JS images that are not in the DOM to affect the page loading UI. But that is what I experienced until I killed the requests. Probably not a bad idea to kill them anyways, though. – trlkly Aug 27 '16 at 03:23
  • @trlkly - I removed the `img.src = ""` from my answer because that seems much worse (in stupid browsers) than a little page UI indicates the page hasn't loaded yet). Those are both browser bugs. – jfriend00 Aug 27 '16 at 03:29
  • I don't agree. The UI bug is front facing, so users will notice. And, like I said, you should close out the request, so it doesn't continue indefinitely, possibly piling up open requests. Requesting another file is relatively harmless, and any browser that does that is failing the HTML5 spec. If both Chrome and Firefox act in the same way on the UI thing, then it is a de facto standard, even if we both think it's wrong. – trlkly Aug 27 '16 at 03:44
  • @trlkly - I don't think it's a good thing to cause another request to be fired when the last one you just had timed out. I'd rather find another way to kill the image loading. Will take some experimentation to see what other options might work. – jfriend00 Aug 27 '16 at 05:20
  • @trlkly - One idea. I wonder what happens if you set the image URL to an illegal URL, not just a non-existent destination, but a URL that can't be properly parsed. The client would discover that before launching any sort of http request. Have to do some testing when I have time. – jfriend00 Aug 27 '16 at 05:29
  • @trlkly - It seems to work in Chrome and Firefox when you set `.src` to an illegally constructed URL. They both report immediate DNS failure so no http request sent and the page loading animation stops. I'll have to play with that some more to see if it's a better solution. – jfriend00 Aug 27 '16 at 05:51
  • @trlkly - Modified answer to set `.src` to URL with an illegal DNS name in it so it cancels the previous loading and then fails immediately before any http request is sent. It works in all the browsers I've tried, particularly Firefox and Chrome where the page loading spinner would not previously have stopped. – jfriend00 Aug 27 '16 at 07:44
  • Shouldn't this also check for SVGs? – Choylton B. Higginbottom Jan 14 '20 at 18:47
  • @ChoyltonB.Higginbottom - It could probably be extended to include SVGs if you want. The original question asked about images with a few known extensions and that's what I was answering here 7+ years ago. – jfriend00 Jan 14 '20 at 22:18
  • Hey, it does not cover the following case, this is a gif url: https://media1.tenor.com/images/c19bc2a2d850b8ce8634e72a213bcb96/tenor.gif?itemid=10279186 – RainCast Aug 27 '20 at 23:38
  • @RainCast - That web server is doing something a bit odd. When you go to that URL in a browser, the website it rendering a web page, not just an image. – jfriend00 Aug 27 '20 at 23:47
  • @jfriend00 the thing is... you can actually set img src to this url, and it works... – RainCast Aug 28 '20 at 00:31
  • @jfriend00 btw do you have iPhone/iPad, I just noticed that your pixel art avatar looked like the kind of art my app creates... https://www.google.com/search?q=new+pixels&sxsrf=ALeKk037OXnxmAUf-KDoBRoIKpL5LBBdkA:1598574727467&source=lnms&tbm=isch&sa=X&ved=2ahUKEwiQ6pv20rzrAhWYsp4KHTkjBHwQ_AUoAXoECA0QAw&biw=2133&bih=1076 – RainCast Aug 28 '20 at 00:32
  • @RainCast - No. I'm an Android person. Don't remember what site I made the avatar on. – jfriend00 Aug 28 '20 at 00:37
  • @RainCast - Well, your URL seems to work just fine for me with the solution in this answer: http://jsfiddle.net/jfriend00/uaf2kmsg/2/. I don't know what exactly you think isn't working. Regardless keep in mind that the server behind this is doing some sort of request sniffing and is sometimes returning a web page and sometimes returning an image for the same URL. – jfriend00 Aug 28 '20 at 00:40
8

For validating image url string with regex, it's simple.

url.match(/^https?:\/\/.+\/.+$/)

All we're checking is that the url has a protocol https://, hostname foobar.com, slash / and then image name. No need to check image extension (png, jpg ...) because it is not required and browsers check image type by it's headers.

To check if image exist, attach its url to an Image constructor and check if it errors or not.

const doesImageExist = (url) =>
  new Promise((resolve) => {
    const img = new Image();

    img.src = url;
    img.onload = () => resolve(true);
    img.onerror = () => resolve(false);
  });
Caleb Taylor
  • 2,670
  • 2
  • 21
  • 31
8

use the HEAD http request method to check the contenttype...

$.ajax({
  type: "HEAD",
  url : "urlValue",
  success: function(message,text,response){
     if(response.getResponseHeader('Content-Type').indexOf("image")!=-1){
           alert("image");
    }
  } 
});

to check whether the string contains that extenstions you can use the inArray method,

function checkUrl(url){
   var arr = [ "jpeg", "jpg", "gif", "png" ];
   var ext = url.substring(url.lastIndexOf(".")+1);
   if($.inArray(ext,arr)){
     alert("valid url");
     return true;
  }
}

edit: updated typo

cch
  • 3,336
  • 8
  • 33
  • 61
redDevil
  • 1,909
  • 17
  • 25
7

A more flexible solution, suporting query params after file extension:

function isImgLink(url) {
    if(typeof url !== 'string') return false;
    return(url.match(/^http[^\?]*.(jpg|jpeg|gif|png|tiff|bmp)(\?(.*))?$/gmi) != null);
}

console.log(isImgLink('https://example.com/img.jpg')); // true
console.log(isImgLink('https://example.com/any-route?param=not-img-file.jpg')); // false
console.log(isImgLink('https://example.com/img.jpg?param=123')); // true
Maikon Matheus
  • 669
  • 7
  • 5
4
let url = "folder/myImage.png";
if ( isValidImageURL(url) ){
    // do something if url is valid image url.
}

function isValidImageURL(str){
    if ( typeof str !== 'string' ) return false;
    return !!str.match(/\w+\.(jpg|jpeg|gif|png|tiff|bmp)$/gi);
}
1

If you want to check that the string starts with http you can use

url.match(/^http.*\.(jpeg|jpg|gif|png)$/) != null
Diego Poveda
  • 110
  • 5
0

This might not be the most optimal way or it might not even work for your use case. But this sure is the easiest and can work with any image file, it can also check if that image exists.

All you need to do is Just make a hidden image element with an onerror property(or use an event handler)

<img hidden src="#" onerror="do_something()">

then just change the image's src attribute when you want to validate an image, if the image is not valid the "onerror" event will be called, which you can then use to handle another event