1

I have generally run across two methods, depending on server configuration, of remotely checking the availability of a CDN-hosted script using PHP. One is cURL, the other is fopen. I've combined the two functions I use in their respective cases like so:

function use_cdn(){
   $url = 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js'; // the URL to check against
   $ret = false;
   if(function_exists('curl_init')) {
      $curl = curl_init($url);
      curl_setopt($curl, CURLOPT_NOBODY, true);
      $result = curl_exec($curl);
      if (($result !== false) && (curl_getinfo($curl, CURLINFO_HTTP_CODE) == 200)) $ret = true;   
      curl_close($curl);
   }
   else {
      $ret = @fopen($url,'r');
   }
   if($ret) {
      wp_deregister_script('jquery'); // deregisters the default WordPress jQuery
      wp_register_script('jquery', $url); // register the external file
      wp_enqueue_script('jquery'); // enqueue the external file
   }
   else {
      wp_enqueue_script('jquery'); // enqueue the local file
   }
}

...but I'm not looking to reinvent the wheel. Is this a good, solid technique or can anyone offer pointers as to how to simplify/streamline the process?

Isaac Lubow
  • 3,557
  • 5
  • 37
  • 53

1 Answers1

1

Using get_headers() we can issue a HEAD request and check the response code to see if the file is available, and also will allow us to see if network or DNS is down since it will cause get_headers() to fail (keep the @ sign to suppress PHP error if domain is not resolvable, which will cause it to return FALSE in that case and thus load local file:

function use_cdn()
{
    $url = 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js'; // the URL to check against
    $online = FALSE;

    if(function_exists('curl_init')) 
    {
        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_NOBODY, TRUE);
        $result = curl_exec($curl);
        if ((FALSE !== $result) && ('200' == curl_getinfo($curl, CURLINFO_HTTP_CODE)))
        {
            $online = TRUE;
        }
        curl_close($curl);
    } 
    else if (ini_get('allow_url_fopen'))
    {
        stream_context_set_default(array('http' => array('method' => 'HEAD'))); // set as HEAD request
        $headers = @get_headers($url, 1); // get HTTP response headers
        if ($headers && FALSE !== strpos($headers[0], '200')) // if get_headers() passed and 200 OK
        {
            $online = TRUE;
        }
    }

    if ($online)
    {
        wp_deregister_script('jquery'); // deregisters the default WordPress jQuery
        wp_register_script('jquery', $url); // register the external file
    }
    wp_enqueue_script('jquery'); // enqueue registered files
}

get_headers() would be faster as it is a build in function, opposed to having to load a PECL extension such as cURL. As for fopen() well the task you need to do is check the response headers, get_headers()'s only use is to do just that, fopen() can't get headers, and cURL has other uses not to mention the unnecessary overhead and don't specialize in getting headers so it would be the most suitable choice to use in this case.

kittycat
  • 14,983
  • 9
  • 55
  • 80
  • I like that. Is there any advantage to using `get_headers()` as opposed to `fopen` or `cURL`? Is there a de facto standard? – Isaac Lubow Dec 12 '12 at 11:47
  • get_headers() would be faster as it is a build in function, opposed to having to load a PECL extension such as cURL. As for fopen() well the task you need to do is check the response headers, get_headers()'s only use is to do just that, fopen() can't get headers, and cURL has other uses not to mention the unnecessary overhead and don't specialize in getting headers so it would be the most suitable choice to use in this case. – kittycat Dec 12 '12 at 12:10
  • Well, that's great! Accepted. Maybe put a note into your answer that explains those advantages? – Isaac Lubow Dec 12 '12 at 15:39
  • Interestingly enough, the server I'm working on at the moment doesn't execute `get_headers()` requests. So if anything, I'm forced to fall back to the two other methods of checking for a 200 response. Guess there isn't a silver bullet for this problem after all. – Isaac Lubow Dec 13 '12 at 12:58
  • It would appear that `get_headers()` is better than `fopen()` so it should simply replace `fopen()` in my original answer for a robust solution. What do you think? – Isaac Lubow Dec 13 '12 at 13:33
  • What version of PHP are you running? Also are you getting an error with above code? If you don't have it it should error with fatal (remove the @) to check. – kittycat Dec 13 '12 at 19:47
  • That's the first thing I did - no errors, it just falls back. It's some server config (I've found it's common on shared hosting) that prevents PHP from `fopen`ing or `get_headers`ing at all. In these cases I've found `cURL` is a decent backup solution. – Isaac Lubow Dec 14 '12 at 03:21
  • I think you have http://us3.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen to FALSE set it to TRUE if it is not and try again. – kittycat Dec 14 '12 at 03:33
  • I can't just set it to true. It's my client's shared webhost and while I can edit `.htaccess` in the site root to enable `fopen`, it doesn't help the function in my question be robust. – Isaac Lubow Dec 14 '12 at 06:48
  • UPDATE: this host prohibits `fopen` as well as messing with `php.ini` and `.htaccess`. While this solution is concise, the function in my question is only robust if I include `cURL` as another method... – Isaac Lubow Dec 14 '12 at 08:15
  • 1
    Well if you really want robust code you would not use cURL either as it can be disabled or not available on hosts as well. What I would do is maybe use all three, in order of most efficient to least efficient and check to see if each is available by using function_exists() for cURL as you did, and checking ini_get('allow_url_fopen') == '1' for fopen() and get_headers(), that way you can fallback to another, while making sure the most efficient methods are tried first. – kittycat Dec 14 '12 at 08:43
  • You can't guarantee a host will even have all three available, your current host is one step away from being like that. Have you considered client-side checking? See: http://stackoverflow.com/q/7383163/1592648 – kittycat Dec 14 '12 at 08:54
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/21166/discussion-between-isaac-lubow-and-cryptic) – Isaac Lubow Dec 15 '12 at 03:02