Curl HTTP Client 2.0

It’s been a while since I last updated my Curl HTTP Client class. That’s the class that we’ve been using for years now, for all kinds of site scrapping, bulk domain registration without API, … and even today we use it as a part of core in our brand new Payment system.

Since I had some spare time this weekend, I finally managed to merge some of updates we’ve created during all these years and put a class to github so I can do frequent updates regularly. Don’t worry, class has retained most of it’s previous functionality explained here so update to latest version shouldn’t cause any problem.

Here’s the GitHub page: https://github.com/dinke/curl_http_client. Feel free to use it in your own projects and send in your comments.

Validating an integer with PHP

When I started writing this post I wasn’t sure should I put this into programming category or fun … I mean, validating if passed variable is integer aka whole number, how hard can it be? It appears not really easy in PHP :)

First off some background, I needed to validate an array with db key values (like array(1,2,6,7,…n)), so I thought of using simple function like array_filter with callback, something like:

array_filter($foo_array, 'is_int');

where is_int is callback, calling built in is_int function for each array value in order to filter out non int values.

The problem is (yes after 10 years dealing with PHP I am aware of that), PHP doesn’t treat int and string numbers the same, so string ’42′ wouldn’t be recognized as integer.

is_int('42'); //false
is_int(42); //true

To make things more “interesting” for programmers, if you have integer form data like age, year or whatever, they will be sent trough $_POST/$_GET/$_REQUEST arrays as ‘string numbers’ (so string ’42′ not int 42).

There is nice function to deal with such things and it’s name is is_numeric … but it only checks if string is actually number, so float values will be evaluated to true as well. ctype_digit on the other hand is opposite of is_int, it will only return true if test variable is string number, so ’42′ would evaluate to true, but 42 to false.

ctype_digit('42'); //true
ctype_digit(42);//false

And to make things even worse, PHP is silently converting really big integers to float (those bigger than PHP_INT_MAX const) so guess what would you get for number like is_int(23234234234235334234234)? Yep, false :)

$var = PHP_INT_MAX;
var_dump($var++); //true
var_dump($var); //false it's float now!

Yeah I know, you could cast var to int and do is_int … or cast var to string and do ctype_digit … and other dirty hacks… but what if someone smart from PHP team had decided to let say add 2nd argument to is_int check so you can check for type in some kind of ‘non strict’ mode, so string ’42′ is actually evaluated as integer? Something like this in C I guess:

function is_int(int var, int strict = 1)
{
   //if strict is false evaluate string integers like '42' to true!
}

All in all (at least to me), the easiest way to validate whether a variable is whole number (aka string or integer string) is with regular expression. Something like this:

/**
 * Test if number is integer, including string integers
 * @param mixed var
 * @return boolean
 */
function isWholeNumber($var)
{
	if(preg_match('/^\d+$/', $var))
	{
		return true;
	}
	else
	{
		return false;
	}
}

Someone from PHP dev team should really consider fixing this.

Debugging with Xdebug and Eclipse on Mac

In my previous posts I explained how to install MacPorts and setup typical Apache/PHP setup with it. Now we’re going to start with something more serious, something that sooner or later every PHP developer will have to deal with. Debugging! And yes when I say debugging I didn’t mean echoing or using var_dump ;)

First off some background info. As far as I know, the very first PHP IDE which actually had debugger built in was Zend Studio. I’ve been using ZDE 5.2.x for very long time, but since Zend stopped supporting it, it was very difficult to continue using it. On Snow Leopard it required some nasty Java hacks to make it working, and any Java update would break it. It was obvious that time of ZDE 5.x was over so I had to pick something new. My choice was Eclipse (I didn’t see any point in paying Zend extra fee for IDE based on Eclipse) so I downloaded Eclipse Hellios release from Zend PDT pages. Unfortunately it was really slow and buggy so after a while I’ve decided to download “classic” Eclipse and get PHP Dev SDK installed manually. Somehow it worked much better for me and since there is new Eclipse Indigo 3.7.1 release right now, I’ve decided to wrote detailed explanation how to install it. In case you already have Eclipse installed and you’re happy with it, just skim to Xdebug setup part.

Setting up Eclipse
————————-
So, let’s download Eclipse 3.7.1 classic and unpack it to some dir. I prefer to use my home dir (which is /Users/dinke/eclipse) but you can pick any, just copy files there and run Eclipse application from that folder. On first run it will ask you about workspace (which is place where Eclipse keeps some internal files), I used /Users/dinke/workspace but you can use any location that suit you. Eclipse will start with Welcome window that we are going to close for now (you can always get it reopened by choosing Help->Welcome)

Eclipse Startup

Now it’s time to download and install PHP Development Tools SDK. So open Help -> Install New Software. Pick Indigo from “work with” drop-down and when list bellow gets updated, go to Programming Languages and check box next to PHP Development Tools SDK as in image bellow.

PDT Startup

Now click next, accept terms and Finish, and PHP tools will be installed. After installation is done (it may take some time), you’ll be offered to restart Eclipse, so do it immediately. After Eclipse has been restarted we are going to switch to PHP perspective. So click to “Open Perspective” icon in upper right corner of Eclipse and pick “Other”. There you’ll be offered options similar as in image bellow:

PHP Perspective

Pick PHP click OK and we’re done with Eclipse setup. Congratulations! Now you can tweak Eclipse to your own preferences (Eclipse->Preferences) or import/start new project and start playing with code.

Xdebug
————
Now we’re going to deal with Xdebug part. First we have to install it, and we’re going to use MacPorts. If you don’t have MacPorts installed just look at my previous post about it.

So, start terminal and type this:

sudo port install php5-xdebug

Restart Apache (sudo /opt/local/apache2/bin/apachectl restart) and make sure that you have proper Xdebug section on phpinfo page (see bellow):

phpinfo

Now we need to add some configuration options to php.ini file, so let’s add this to the bottom of php.ini file (in my case located at /opt/local/etc/php5/php.ini):

[xdebug]
zend_extension="/opt/local/lib/php/extensions/no-debug-non-zts-20090626/xdebug.so"
xdebug.profiler_output_dir = "/tmp/xdebug/"
xdebug.profiler_enable = On
xdebug.remote_enable=On
xdebug.remote_host="localhost"
xdebug.remote_port=9000
xdebug.remote_handler="dbgp"
xdebug.idekey=ECLIPSE_DBGP 

and restart Apache again.

Now let’s configure Eclipse debugging options. Open Eclipse Preferences and then PHP->Debug and instead of Zend pick XDebug from PHP Debugger drop down.

eclipse_debug

Click Configure link next to dropdown, select Xdebug and click configure button again and make sure that in Accept remote session (JIT) is set to any (see image bellow).

eclipse_xdebug_settings

And this is it! Hooray!

Now let’s see how it’s actually working, we’re going to use so called “remote” debugging which allow us to actually debug directly from browser (there’s even firefox ext for that), however I prefer to insert my URL’s directly to configuration options. So select Run->Debug As from the menu and pick PHP Web Page. You will be asked to insert URL and then Debugging perspective will be opened along with editor. There you have ability to step into code, setup break points and watch variables on the right.

debugger

Happy Debugging :)

Useful Links:
Eclipse/Xdebug Remote debugging on Windows
Xdebug

Installing Apache and PHP with MacPorts

As you probably already know, Mac OS X comes with Apache and PHP preinstalled, all you have to do in order to turn it on is to turn Web Sharing On in System Preferences and do some changes in httpd.conf/php.ini files.

web sharing

You can probably find tons of tutorials on that topic (try this one for example) so not gonna waste my time on explaining how to do it.

Problem with bundled PHP/Apache setup on Mac is lack of flexibility. You already have most of extensions you’d ever need enabled, but there are still some missing, and if you want something not already there, you’re out of luck. For example recently I’ve started working on new project which requires memcache and xdebug support and there isn’t any way to have them enabled in bundled Apache/PHP setup.

Mac Ports to the Rescue
——————————————
In my previous post I’ve explained how to setup MacPorts on Mac OS X. Now we’re going to use it in order to setup fully working and flexible “LAMP” environment. Speaking of LAMP, I assume that you already have MySQL installed which is really easy to do with pkg installer available at http://dev.mysql.com/downloads/mysql/ (just download DMG Archive, unpack and run installer).

We will start our port setup by installing Apache 2. So open terminal and type this:

sudo port install apache2

After Apache is successfully installed we will deal with PHP 5 part. There are many extensions that we may get installed, but great thing with MacPorts is that you don’t have to install all of them at once, it’s quite okay to install them later. So we’re going to start with really basic PHP 5 setup by running this cmd in terminal:

sudo port install php5 +apache2 +mysql5

and you’ll get really long output which tale looks like this:

...
Warning: php5 installs files outside the common directory structure.
--->  Installing php5 @5.3.8_0+apache2
--->  Activating php5 @5.3.8_0+apache2
To customize php, copy
/opt/local/etc/php5/php.ini-development (if this is a development server) or
/opt/local/etc/php5/php.ini-production (if this is a production server) to
/opt/local/etc/php5/php.ini and then make changes.

If this is your first install, you need to activate PHP in your web server.

To enable PHP in Apache, run
  cd /opt/local/apache2/modules
  /opt/local/apache2/bin/apxs -a -e -n "php5" libphp5.so
--->  Cleaning php5
Dragan-Dinics-MacBook-Pro:~ dinke$

As you can see at the end of output, we also need to run some cmd’s in order to enable PHP in Apache, so execute these in terminal:

cd /opt/local/apache2/modules
sudo /opt/local/apache2/bin/apxs -a -e -n “php5″ libphp5.so

and you’ll get output as bellow:

Dragan-Dinics-MacBook-Pro:~ dinke$ cd /opt/local/apache2/modules
Dragan-Dinics-MacBook-Pro:modules dinke$ sudo /opt/local/apache2/bin/apxs -a -e -n "php5" libphp5.so
[activating module `php5' in /opt/local/apache2/conf/httpd.conf]
Dragan-Dinics-MacBook-Pro:~ dinke$

Now we need to edit /opt/local/apache2/conf/httpd.conf and tweaks it to our needs. You will probably want to change default DocumentRoot, for example my Doc root is under /Users/dinke/htdocs so on my Mac it’s set like this:

DocumentRoot "/Users/dinke/htdocs"

Note: If you change DocumentRoot path don’t forget to change path in Directory directive as well (should be the same as path in DocumentRoot).

Make sure that that in LoadModule section you have proper PHP modul:

LoadModule php5_module modules/libphp5.so

and last but not least, add proper entries in block to tell Apache to use PHP module for processing php files.

AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps

That should be all regarding Apache conf.

Now copy PHP.ini file to proper location:

sudo cp /opt/local/etc/php.ini-dist /opt/local/etc/php.ini

and edit it if you want now or leave it for later, up to you.

Time to start Apache now! Let’s run this cmd:

sudo /opt/local/apache2/bin/apachectl start

and if you don’t get any error message, that means that Apache is up and running. If you do, check again your config and make sure that you don’t have any errors.

Now create usual phpinfo() page and save it in your docroot (/Users/dinke/htdocs/test.php in my example), and try to see if it works:

http://localhost/test.php

phpinfo page

If you get usual PHPinfo page simmilar as above, your installation was successful. Well done!

Now what is great with MacPorts setup is that you can now add more extensions easily. For example if you search for php5 extensions you will get 111 ports!

sudo port search php5

php5 @5.3.8 (lang, php, www)
PHP: Hypertext Preprocessor

php5-amf @0.9.2 (php, devel)
ActionScript Message Format extension

php5-apc @3.1.9 (php, devel)
Alternative PHP Cache

php5-bbcode @1.0.2 (php, devel)
BBCode parsing Extension
...
Found 111 ports.

So for example if you want mcrypt module installed, all you have to do is to run this:

sudo port install php5-mcrypt

and you’ll get output like this:

Dragan-Dinics-MacBook-Pro:~ dinke$ sudo port install php5-mcrypt
--->  Computing dependencies for php5-mcrypt
--->  Dependencies to be installed: libmcrypt
--->  Fetching archive for libmcrypt
--->  Attempting to fetch libmcrypt-2.5.8_1.darwin_10.x86_64.tbz2 from http://packages.macports.org/libmcrypt
--->  Attempting to fetch libmcrypt-2.5.8_1.darwin_10.x86_64.tbz2.rmd160 from http://packages.macports.org/libmcrypt
--->  Installing libmcrypt @2.5.8_1
--->  Activating libmcrypt @2.5.8_1
--->  Cleaning libmcrypt
--->  Fetching archive for php5-mcrypt
--->  Attempting to fetch php5-mcrypt-5.3.8_0.darwin_10.x86_64.tbz2 from http://packages.macports.org/php5-mcrypt
--->  Fetching php5-mcrypt
--->  Verifying checksum(s) for php5-mcrypt
--->  Extracting php5-mcrypt
--->  Configuring php5-mcrypt
--->  Building php5-mcrypt
--->  Staging php5-mcrypt into destroot
--->  Installing php5-mcrypt @5.3.8_0
--->  Activating php5-mcrypt @5.3.8_0
--->  Cleaning php5-mcrypt

Now restart Apache, and you should be able to see mcrypt module activated on phpinfo page. Enjoy!

mcrypt

Installing MacPorts

The MacPorts Project is an open-source community initiative to design an easy-to-use system for compiling, installing, and upgrading open source software on Mac OS X. As you’ll be able to see later, it’s easy to use but still very powerful.

Unless you already have it installed, the very first step in installing MacPorts actually starts with installing Xcode Developer Tools which is not installed by default. It comes with Mac OS X Applications DVD but it’s probably the best idea to download the latest version from Apple site. There are currently two branches of Xcode, 3.2.x and 4.1.x. If you are on Snow Leopard get Xcode 3, if you’re on Lion get Xcode 4.1, both are available on Apple Developers site, and unless you already have an account, you will need to register first.

After you’re logged in on Apple Dev site, you can download and install Xcode 3.2 from this link and then run Mac software update to update it to latest version. If you’re on Lion you can get Xcode 4.1 from this link or get it from App Store.

Now let’s deal with MacPorts installation. The easiest way to install it is with DMG package installer. Again if you’re on Snow Leopard get it from here, Lion version can be downloaded from here. Run installer which will setup everything automatically (copy files and modify your .bash_profile file by adding proper PATH variable for MacPorts tree which is something like export PATH=/opt/local/bin:/opt/local/sbin:$PATH).

Now open terminal and run this cmd:

sudo port -v selfupdate

This is how output looked on my system:

Dragan-Dinics-MacBook-Pro:~ dinke$ sudo port -v selfupdate
Password:
--->  Updating MacPorts base sources using rsync
receiving file list ... done
base.tar

sent 10864 bytes  received 111 bytes  4390.00 bytes/sec
total size is 3226624  speedup is 294.00
receiving file list ... done
base.tar.rmd160

sent 64 bytes  received 116 bytes  72.00 bytes/sec
total size is 512  speedup is 2.84
MacPorts base version 2.0.3 installed,
MacPorts base version 2.0.3 downloaded.
--->  Updating the ports tree
Synchronizing local ports tree from rsync://rsync.macports.org/release/tarballs/ports.tar
receiving file list ... done
ports.tar

sent 47525 bytes  received 5715 bytes  9680.00 bytes/sec
total size is 45947904  speedup is 863.03
receiving file list ... done
ports.tar.rmd160

sent 64 bytes  received 636 bytes  280.00 bytes/sec
total size is 512  speedup is 0.73
Creating port index in /opt/local/var/macports/sources/rsync.macports.org/release/tarballs/ports

Total number of ports parsed:   0 
Ports successfully parsed:      0 
Ports failed:                   0 
Up-to-date ports skipped:       12335

--->  MacPorts base is already the latest version

The ports tree has been updated. To upgrade your installed ports, you should run
  port upgrade outdated
Dragan-Dinics-MacBook-Pro:~ dinke$

If you didn’t get any error message, that’s it you’re done. Congratulations!

Now let’s deal with the installation of some apps, and we will start with wget which is very nice cli tool for downloading stuff and somehow it is not available on Mac by default. So let’s start by issuing port search cmd:

Dragan-Dinics-MacBook-Pro:/ dinke$ port search wget
gwget @1.0.4 (gnome, net)
    Gwget is a Download Manager for Gnome 2. It uses wget as a backend.

wget @1.13.4 (net, www)
    internet file retriever

wgetpro @0.1.3 (net, www)
    advanced internet file retriever

wput @0.6.2 (net)
    wput is like wget but is for uploading files to ftp-servers

Found 4 ports.
Dragan-Dinics-MacBook-Pro:/ dinke$

So it’s there in ports (internet file retriever), we’re going to install it by issuing port install cmd. Since this will require root permissions you will have to do it with sudo:

Dragan-Dinics-MacBook-Pro:/ dinke$ sudo port install wget
Password:
--->  Computing dependencies for wget
--->  Dependencies to be installed: gnutls libgcrypt libgpg-error libtasn1 lzo2
--->  Fetching archive for libgpg-error
--->  Attempting to fetch libgpg-error-1.10_0.darwin_10.x86_64.tbz2 from http://packages.macports.org/libgpg-error
--->  Attempting to fetch libgpg-error-1.10_0.darwin_10.x86_64.tbz2.rmd160 from http://packages.macports.org/libgpg-error
--->  Installing libgpg-error @1.10_0
--->  Activating libgpg-error @1.10_0
--->  Cleaning libgpg-error
--->  Fetching archive for libgcrypt
--->  Attempting to fetch libgcrypt-1.5.0_0.darwin_10.x86_64.tbz2 from http://packages.macports.org/libgcrypt
--->  Attempting to fetch libgcrypt-1.5.0_0.darwin_10.x86_64.tbz2.rmd160 from http://packages.macports.org/libgcrypt
--->  Installing libgcrypt @1.5.0_0
--->  Activating libgcrypt @1.5.0_0
--->  Cleaning libgcrypt
--->  Fetching archive for libtasn1
--->  Attempting to fetch libtasn1-2.9_0.darwin_10.x86_64.tbz2 from http://packages.macports.org/libtasn1
--->  Attempting to fetch libtasn1-2.9_0.darwin_10.x86_64.tbz2.rmd160 from http://packages.macports.org/libtasn1
--->  Installing libtasn1 @2.9_0
--->  Activating libtasn1 @2.9_0
--->  Cleaning libtasn1
--->  Fetching archive for lzo2
--->  Attempting to fetch lzo2-2.05_1.darwin_10.x86_64.tbz2 from http://packages.macports.org/lzo2
--->  Attempting to fetch lzo2-2.05_1.darwin_10.x86_64.tbz2.rmd160 from http://packages.macports.org/lzo2
--->  Installing lzo2 @2.05_1
--->  Activating lzo2 @2.05_1
--->  Cleaning lzo2
--->  Fetching archive for gnutls
--->  Attempting to fetch gnutls-2.8.6_1.darwin_10.x86_64.tbz2 from http://packages.macports.org/gnutls
--->  Attempting to fetch gnutls-2.8.6_1.darwin_10.x86_64.tbz2.rmd160 from http://packages.macports.org/gnutls
--->  Installing gnutls @2.8.6_1
--->  Activating gnutls @2.8.6_1
--->  Cleaning gnutls
--->  Fetching archive for wget
--->  Attempting to fetch wget-1.13.4_0+ssl.darwin_10.x86_64.tbz2 from http://packages.macports.org/wget
--->  Attempting to fetch wget-1.13.4_0+ssl.darwin_10.x86_64.tbz2.rmd160 from http://packages.macports.org/wget
--->  Installing wget @1.13.4_0+ssl
--->  Activating wget @1.13.4_0+ssl
To customize wget, you can copy wgetrc.sample to wgetrc
in /opt/local/etc and then make changes.
--->  Cleaning wget
Dragan-Dinics-MacBook-Pro:/ dinke$ 

Now issue wget cmd and you’ll get output like this:

Dragan-Dinics-MacBook-Pro:/ dinke$ wget
wget: missing URL
Usage: wget [OPTION]... [URL]...

Try `wget --help' for more options.
Dragan-Dinics-MacBook-Pro:/ dinke$

which means that wget tool is successfully installed and ready to be used for downloading stuff from the Internet. Enjoy!

Useful links:
http://www.macports.org/install.php
http://guide.macports.org

Next Page »