cURL: follow locations with safe_mode enabled or open_basedir set

cURL is a tool to connect to a remote server and load data from it while schemes like HTTP, HTTPS, FTP, gopher, telnet, DICT, FILE, LDAP and more are supported for the request URI.

PHP has built-in support by providing its users a layer upon the underlying libcurl library. Here is an example how cURL is used in PHP:

$ch = curl_init("http://example.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
curl_close($ch);

The option CURLOPT_RETURNTRANSFER advices PHP to return the result after executing curl_exec() on success and FALSE else. If this option is ommitted it would return TRUE instead of the result.

At some point you need to follow a location. This is the case if a server you are connecting to is replying with a location redirect. In a HTTP response the server would reply with a 301 or 302 status code and the HTTP header Location pointing to the new URI. In the code the option CURLOPT_FOLLOWLOCATION needs to be set to allow libcurl to follow the redirect.

$ch = curl_init("http://example.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$data = curl_exec($ch);
curl_close($ch);

However if your web server has safe_mode activated or open_basedir set then CURLOPT_FOLLOWLOCATION won’t have any effect. The below warning will appear and libcurl won’t follow the new location.

Warning: curl_setopt() [function.curl-setopt]: CURLOPT_FOLLOWLOCATION
cannot be activated when in safe_mode or an open_basedir is set in ...

This blog post shows you a workaround by changing the server configuration and putting the loader script to a directory defined in open_basedir. Unfortunately many websites are hosted on a shared host. Hence most people can’t just alter something in a configuration file but rather need a user-space solution.

One solution is to follow redirects manually by examining the server response and send the request to the new location again. The next sample code does exactly this. The function curl_exec_follow is passed two arguments, one is the cURL handler and the second the maximum amount of allowed redirects. If a server response contains a redirect location the script also checks if it’s a URL or a relative path to the resource.

function curl_exec_follow($ch, &$maxredirect = null) {

  $mr = $maxredirect === null ? 5 : intval($maxredirect);

  if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) {

    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $mr > 0);
    curl_setopt($ch, CURLOPT_MAXREDIRS, $mr);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

  } else {

    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);

    if ($mr > 0)
    {
      $original_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
      $newurl = $original_url;

      $rch = curl_copy_handle($ch);

      curl_setopt($rch, CURLOPT_HEADER, true);
      curl_setopt($rch, CURLOPT_NOBODY, true);
      curl_setopt($rch, CURLOPT_FORBID_REUSE, false);
      do
      {
        curl_setopt($rch, CURLOPT_URL, $newurl);
        $header = curl_exec($rch);
        if (curl_errno($rch)) {
          $code = 0;
        } else {
          $code = curl_getinfo($rch, CURLINFO_HTTP_CODE);
          if ($code == 301 || $code == 302) {
            preg_match('/Location:(.*?)\n/', $header, $matches);
            $newurl = trim(array_pop($matches));

            // if no scheme is present then the new url is a
            // relative path and thus needs some extra care
            if(!preg_match("/^https?:/i", $newurl)){
              $newurl = $original_url . $newurl;
            }
          } else {
            $code = 0;
          }
        }
      } while ($code && --$mr);

      curl_close($rch);

      if (!$mr)
      {
        if ($maxredirect === null)
        trigger_error('Too many redirects.', E_USER_WARNING);
        else
        $maxredirect = 0;

        return false;
      }
      curl_setopt($ch, CURLOPT_URL, $newurl);
    }
  }
  return curl_exec($ch);
}

This function is used in place of curl_exec() and doesn’t need extra user privileges as you would need to change the server configuration.

$ch = curl_init("http://example.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec_follow($ch);
curl_close($ch);

Hopefully this helped you.

DeliciousDiggTechnorati FavoritesRedditLinkedInFacebookSpurlTwitterWebnewsYiGGMySpaceYahoo BookmarksFriendFeedGoogle BookmarksLiveJournalShare

Arch Linux: failed to load module `zsh/computil’

If you’ve recently updated zsh and used tab auto-complete you’re getting the following error message.

➜  zsh  cd
_tags:36: failed to load module `zsh/computil': /usr/lib/zsh/4.3.15/zsh/computil.so: cannot open shared object file: No such file or directory
_tags:51: failed to load module `zsh/computil': /usr/lib/zsh/4.3.15/zsh/computil.so: cannot open shared object file: No such file or directory
_tags:51: command not found: comptry
_tags:51: command not found: comptry
_tags:55: command not found: comptry
_tags:60: command not found: comptags
_tags:67: command not found: comptags
_tags:36: command not found: comptags
_tags:51: command not found: comptry
_tags:51: command not found: comptry
_tags:51: command not found: comptry
_tags:55: command not found: comptry
_tags:60: command not found: comptags
_tags:67: command not found: comptags
_tags:36: command not found: comptags
_tags:51: command not found: comptry
_tags:51: command not found: comptry
_tags:51: command not found: comptry
_tags:55: command not found: comptry
_tags:60: command not found: comptags
_tags:67: command not found: comptags

This can be an indication for a system intrusion. A hacker cracker might have found a workaround for pacman’s signature system who probably did a man-in-the-middle attack by providing you a modified version of zsh which breaks your entire system and is now under control of this hacker cracker.

!! You definitely must reinstall Arch Linux !!

If you don’t, this hacker cracker can do very evil things by using your IP which identifies you if your computer is connected to the internet. Less evil things could be abuse of your IP for spam purpose. The most evil thing he could do is providing the internet with ch**d p*rn. For government agencies it looks like you provided it and it’s you who will be charged with it.

If you’re sure there was no hacker cracker involved, then the reason might be that the zsh version changed. The library moved from


/usr/lib/zsh/4.3.15/zsh/computil.so

to

/usr/lib/zsh/4.3.16/zsh/computil.so

but your current terminal window thinks it’s still in the old place. This can easily be fixed by opening a new terminal window.

DeliciousDiggTechnorati FavoritesRedditLinkedInFacebookSpurlTwitterWebnewsYiGGMySpaceYahoo BookmarksFriendFeedGoogle BookmarksLiveJournalShare

Firefox: This address is restricted

This address uses a network port which is normally used for purposes other than Web browsing. Firefox has canceled the request for your protection.

This message appears if you want to access a website on a non-standard port, e.g. http://example.com:42 .

Being a developer you might run in your non-productive environment a web server listening on such a port. As a workaround you can tweak your firefox by adding the configuration network.security.ports.banned.override to your preferences.

To do so go to about:config, klick on the “I’ll be careful, I promise!” button and right-click any preference. In the appearing context menu click New > String and add the new preference

network.security.ports.banned.override

with a value “1-65000″ or whatever ports you want to access. They don’t describe blocked ports but ports that are considered to be not banned.

I recommend to create a new firefox profile for development and testing purpose and that you only open ports that you really need.

DeliciousDiggTechnorati FavoritesRedditLinkedInFacebookSpurlTwitterWebnewsYiGGMySpaceYahoo BookmarksFriendFeedGoogle BookmarksLiveJournalShare

Arch Linux: Pacman 4.0 upgrade breaks the system

Since yesterday, January 16th, pacman 4 is in the core repository and upgrading to it breaks the system.

If you can wait with any updates, wait. If you must update some packages, only update those which you need to update right now and which don’t affect the system.

To exclude the packages which surely breaks your system, edit your /etc/pacman.conf and add to IgnorePkg all packages related to any package manager stuff and all packages you know that they break something.

IgnorePkg   = pacman package-query yaourt libarchive

If you encounter trouble with other packages, let me know.

If you updated libarchive for whatever reason pacman stops to work while it outputs this error message:

pacman: error while loading shared libraries: libarchive.so.2: cannot open shared object file: No such file or directory

To fix this you have to create a symlink pointing from libarchive.so.2 to libarchive.so.12.0.3. Adapt the version number of according to your installed archive lib. Check this with

ls -l /usr/lib | grep libarchive.so

Now pacman should work again.

Update (Jan 21st):
On my arm-based Archlinux everything went fine when upgrading and generating the keyring. On my desktop I’ve got to fiddle with some configurations but it seems that nothing bigger goes wrong today. Maybe I was completely wrong with my statement “pacman 4 breaks the system” but libarchive really made trouble days ago so it wasn’t a bad choice to wait a little bit.

DeliciousDiggTechnorati FavoritesRedditLinkedInFacebookSpurlTwitterWebnewsYiGGMySpaceYahoo BookmarksFriendFeedGoogle BookmarksLiveJournalShare

Qt: Q_OBJECT macro

I always thought that every class subclassing QObject must contain this macro but this is not completely right. More precisely it is only required if meta-object code has to be produced by the moc tool in order to use the signals and slots mechanism, the run-time type information, the dynamic property system and translating features for internationalization.

Beside that the methods metaObject() and inherits() from QObject as well as className() and newInstance() from QMetaObject also require it.

However the Qt developers strongly recommend that Q_Object is used by every subclass of QObject no matter what of the above features they actually use, also if none is used.

DeliciousDiggTechnorati FavoritesRedditLinkedInFacebookSpurlTwitterWebnewsYiGGMySpaceYahoo BookmarksFriendFeedGoogle BookmarksLiveJournalShare