4

I have a value that may be either an image URL or an image Base64 string. What is the best method to determine which is which? If it's an image URL, the image will already reside on my server.

I've tried doing a preg_match but I think running a preg_match on a potentially huge base64 string will be server intense.

EDIT: The two best methods thus far.

// if not base64 URL
if (substr($str, 0, 5) !== 'data:') {}

// if file exists
if (file_exists($str)) {}
ditto
  • 5,917
  • 10
  • 51
  • 88
  • An image URL will generally start with `http://` or similar; a base64 encoded string won't – Mark Baker Aug 12 '13 at 15:17
  • The image url may be relative. – ditto Aug 12 '13 at 15:18
  • 1
    URLs generally start with a protocol (like `http://`) and `:` is not a valid base64 character. Alternatively, the tld separator `.` is not a valid character either (as in `google.com/foo`), so you can just take a substr (first 100 characters) and check for first instance of `:` or `.` – SheetJS Aug 12 '13 at 15:18
  • If it's a `relative url` test for the existence of an image file using `file_exists()` – Mark Baker Aug 12 '13 at 15:34
  • want do you want to do if a image is based on a data: url? i mean do you also want to validate if the base64 is correct or not? – Raymond Nijland Aug 12 '13 at 16:25

3 Answers3

5

You mean you want to differentiate between

<img src="http://example.com/kittens.jpg" />
and
<img src="data:image/png;base64,...." />

You'd only need to look at the first 5 chars of the src attribute to figure out if it's a data uri, e.g.

if (substr($src, 0, 5) == 'data:')) {
    ... got a data uri ...
}

If it doesn't look like a data uri, then it's safe to assume it's a URL and treat it as such.

Marc B
  • 356,200
  • 43
  • 426
  • 500
0

If those are only two possibilities, you can do something like:

$string = 'xxx';
$part = substr($string, 0, 6); //if an image, it will extract upto http(s):

if(strstr($part, ':')) {
    //image
} else {
    //not an image
}

Explanation: The above code assumes that the input is either a base64 string or an image. If it's an image, it will and should contain the protocol information (including the :). That's not allowed in a base64 encoded string.

Amal Murali
  • 75,622
  • 18
  • 128
  • 150
  • Thanks, but it may be a relative URL. The image may reside on my server. – ditto Aug 12 '13 at 15:29
  • In that case, maybe try to [resolve](http://stackoverflow.com/a/1243431/1438393) and use that? That's not guaranteed to work in all the cases, but it's something you could try. – Amal Murali Aug 12 '13 at 15:38
  • I could do if(file_exists($val)) but if $val is a base64 string, it'll become server intense. – ditto Aug 12 '13 at 15:41
  • Use `strlen()` and check if the string's length is greater than longest image URL in your server -- and if it's **not**: use `file_exists` and check if it exists. – Amal Murali Aug 12 '13 at 15:48
0

You can do this with preg_match(). When preg_match doesn't see the d, the code will stop. if it finds a d not followed by an a it will stop and so on. Also this way you're not doing superfluous math and string parsing:

if(!preg_match('!^data\:!',$str) {
  //image
} else {
  //stream
}

You can also use is_file() which will not return true on directories.

// if file exists and is a file and not a directory
if (is_file($str)) {}
AbsoluteƵERØ
  • 7,816
  • 2
  • 24
  • 35