Showing posts with label php. Show all posts
Showing posts with label php. Show all posts

PHP 5.4 and MySQL 5.5 in CentOS 6.4

Due to some shenanigans in office, unfortunate miscommunication, and effing messed up provisioning, have to redo the LAMP installation again in CentOS 6.4. Installation steps as root shown below.

1. Install the Remi third party repository.
$ rpm -ivh http://rpms.famillecollet.com/enterprise/6/remi/x86_64/remi-release-6.4-1.el6.remi.noarch.rpm

2. Enable the Remi Repository and update.
$ vim /etc/yum.repos.d/remi.repo
$ yum update

3. Install the Apache Web Server, Mysql Database Server, and PHP. Configure and set the MySQL's password as well.
$ yum install httpd php php-mysql mysql-server
$ mysql_secure_installation

4. Enable both web and database server start upon reboot.
$ chkconfig httpd on
$ chkconfig mysql on
$ reboot

REPL for PHP - Part 1 : Built-in Interative Shell

A Read-eval-print loop (REPL) is a simple and quick programming environment for testing short code snippet or debugging. In PHP, there are five REPLs namely PHP's native interactive shell, Boris, Tiny PHP REPL, PHPSH, and Wigwam. Let's go through each one of them.

First, let's start with the default built-in REPL environment which was available since PHP 5.1. For interactive mode (you can scroll back each line of code through history logging in ~/.php_history), just make sure the readline extension is enabled.
$ php -m | grep readline
readline

$ php -a
Interactive shell
php >

One of the nicest feature is auto-completion (just type the tab key), extremely useful if you can't remember the exact functions or classes name.
php > print easter_da
easter_days  easter_date

Another useful feature is setting your viewing pager. Useful when you're expecting long result that spans multiple screens. Unfortunately, this setting is only available from PHP 5.4 onwards.
php > .pager=less
php > phpinfo();

Unfortunately, there are two limitations. First, there is no syntax highlighting support thus making reading the code or result a bit difficulty. Second, you have to manually print out result of every evaluated expression, which is repetitious and troublesome.
php > print_r(new DateTime());
DateTime Object
(
    [date] => 2013-10-13 01:49:44
    [timezone_type] => 3
    [timezone] => Asia/Kuala_Lumpur
)

On array_slice and array_shift Functions

public function query($query) {
    $stmt = $this->pdo->prepare($query);
    $stmt->execute(array_slice(func_get_args(), 1));
    return $stmt;
}
Interesting piece of PHP code shown above. Didn't realize you can use array_slice function to extract portion of an array from func_get_args function. My typical way is just using array_shift function to remove the first element.

Instead of
array_slice(func_get_args(), 1);

you can also obtain the same result (a bit longer) by
$args = func_get_args();
array_shift($args);

However, you just can't simply write in such way show below (the interpreter will throw fatal error) which I am going to elaborate more.
array_shift(func_get_args());

Run your PHP in interactive mode and type the sample code. As shown.
$ php -a
php > print_r(array_shift(array('a', 'b', 'c')));
PHP Fatal error:  Only variables can be passed by reference in php shell code on line 1

Let's assign a temporay variable to the array. Howevery, we only obtain the first element as array_shift function is a modifier function which modify the argument and expect is to be a reference.
php > print_r(array_shift($temp = array('a', 'b', 'c')));
aphp >

The only way is to first assign your array to a variable and modify it.
php > $temp = array('a', 'b', 'c');
php > array_shift($temp);
php > print_r($temp);
Array
(
    [0] => b
    [1] => c
)

Conclusion is if you want a portion of an array, just use array_slice function.

An Integer is Not an Integer

Another day, another unexpected behaviour encountered in  wonderland. Funny that a number returned from a function that looks like an integer is actually not an integer. Let's illustrate this with a simple example.

1. Start the interactive mode.
$ php -a

2. Let's find the square root of number 9, using sqrt function.
php > echo sqrt(9), "\n";
3

3. Obviously 3 is an integer right? Just to confirm, let's use is_int function to check it. Nope, is not.
php > echo is_int(sqrt(9)), "\n";

4. Checking the sqrt function documentation again. It seemed that sqrt will return float data type even though the decimal point is not shown. Let's try with is_float or gettype function.
php > echo is_float(sqrt(9)), "\n";
1
php > echo gettype(sqrt(9)), "\n";
double

Double ? Isn't it supposed to return float ? According to documentation [4], double was used instead of float due to historical reason. Why ? No effing idea what so ever.

5. Still, how we going to check for integer, is this case, to find out which number is the perfect square (an integer is a square of another integer) ? Type casting. See example below.
php > $root = sqrt(9); echo $root == (int)$root, "\n";
1

Another day, another gotcha in PHP world.

Endless PHP Internal Drama

Via HN. Sigh. Endless drama in the PHP  internals. I applaud their efforts (both Anthony and Nikita) to bring more useful and typical programming languages features like generators, function autoloading, and password hashing. to PHP. However, the language itself is slowly morph from a simple procedural web template language into a poor imitation of Java with none of its benefits. The hacked solution of namespace separator. More inconsistency and complexity. Yes, some may argue is a Bikeshed [8] issue and you can choose not to use it. But seriously, backslah (\) ?

The language itself feels like a ship sailing aimlessly in the sea and go where ever the sea wind direct it. Both Rasmus together with Zend should step in and be the Benevolent Dictator for Life (BDFL) instead of letting the community votes decides. Sometimes, unfortunately, decisions are made by those who made the most noise.

Variadic Function

Few years ago, I was introduced to this PHP function func_get_args() by my senior while reading his code (can't remember what or why he used it for). This function allows you to create a function that can take multiple arguments and no argument list declaration in your function signature. Code shown below is an example of a helper function to find the maximum value from a set of number.
function max() {
   $max = -PHP_INT_MAX;
   foreach(func_get_args() as $arg) {
      if ($arg > $max) {
          $max = $arg;
      }
   }
   return $max;
}

echo max(1,5,7,3);
7

Why I brought this up ? I didn't realize that the term "variadic function" is used to describe function that support multiple arguments until I read the Request For Comment (RFC) on the proposal of a new syntax for variadic function for PHP. Historically, variadic function is an old concept that long implemented in C programming language, especially for printf() and scanf() function. Not surprisingly, these two functions also existed in PHP , since it's a C-based programming language.

Back to the RPC. Reading through the discussion in Reddit and the RFC itself. I think is a good idea since we can now enforce type hints and enforcing consistency on interface. However, a feature that is nice to have but only useful for those framework or library writer and not mere library consumer like us.

Debugging Secure Socket Layer (SSL)

Can't sleep. Cleaning up my old notes. Jotted these down last time while writing a PHP script to make secure connection to remote server.

1. Check your PHP's SSL extension infomation.
$ php -r "echo phpinfo();" | grep SSL

2. Check and test remote server SSL using openssl client.
$ openssl s_client -state -quiet -connect google.com:443

3. Check and test remote server ssl using curl.
$ curl --sslv3 https://www.google.com

String to Array in PHP

Another interesting PHP  feature that I didn't realize. String can be accessed by both braces or array. Something I learned from reading my colleague's code. One of the benefit when you worked with people from different coding experiences.

My usual way of converting a string to array is first using str_split, then access individual character as array element. Example as shown.
php > $str = "foobar";
php > print_r(str_split($str));
Array
(
    [0] => f
    [1] => o
    [2] => o
    [3] => b
    [4] => a
    [5] => r
)
php > print_r(str_split($str)[0]);
f

However, the code above is unnecessary if you just want to obtain individual character in a string directly. For examples,

Using curly bracket or braces {}
php > $str = "foobar";
php > print $str{0};
f

Using bracket []
php > $str = "foobar";
php > print $str[0];
f

However, this only works for single-byte encoding strings as documented in the #PHP  manual.
"Internally, PHP strings are byte arrays. As a result, accessing or modifying a string using array brackets is not multi-byte safe, and should only be done with strings that are in a single-byte encoding such as ISO-8859-1." -- php.net, emphasis added

Using GeoIP with PHP - Part 4

It was a fruitful journey trying to install the GeoIP extension. These are some lessons learned from all three previous posts.

If you’re running Ubuntu in live production server, stick to Long Term Support (LTS) distro. Be very conservative, similar to RPM-based distro. Use CentOs and not Fedora for production.

Do not trust the stability of the extension that came bundled from the distro. Ubuntu/Debian always a bit lag behind with the latest fixes. Install your PHP extension using PECL.

Always test your installed PHP extension using the test cases that came together in the source code. The greatest benefit is all these test cases will show the stability of the extension and the correctness of your PHP configuration. Starting from now, any new LAMP installation will be tested with the sample test cases in the PHP source.

Read the bloody changelog. Google the proper keywords. It never occurs to me to google the culprit method name, geoip_db_get_all_info().

Learn some C and how to debug with gdb. I still don’t quite understand C and can’t really backtrace the issue back to the original line of the code. Something to improve upon in the coming future.

I have been using PHP professionally for many years and yet there are still a lot to be learned.

Using GeoIP with PHP - Part 3

Continue from part 3. We will try another approach using plain PHP library file instead of apt-get or pecl as shown in Part 1 and 2. This method is suitable if you don’t have full or root access to your machine. Example is using shared hosting.

Clone the geoip api library.
$ git clone https://github.com/maxmind/geoip-api-php

Try run one of example script.
$ cd geoip-api-php
$ php -f sample_city.php
PHP Fatal error:  Cannot redeclare geoip_country_code_by_name() in /home/kianmeng/project/geoip-api-php/geoip.inc on line 439

Yup, method name conflict. In PHP, all methods are in global namespace, hence the name collision. Which is why they introduce ugly-hack of namespace in PHP to solve this problem. We have to remove our PECL-installed geoip extension in Part 2.
$ sudo pecl uninstall geoip
$ sudo rm -rf /etc/php5/conf.d/geoip.ini

Download and uncompress the sample data file.
$ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
$ gunzip GeoIP.dat.gz

Create this sample test code (test_geoip.php).
<?php
require_once "geoip.inc";

$gi = geoip_open("GeoIP.dat", GEOIP_STANDARD);
echo geoip_country_code_by_name($gi, "php.net"), "\n";
geoip_close($gi);

Run the script.
$ php -f test_geoip.php
US

Another similar sample test code (test_cached_geoip.php) but using memory caching.
<?php
require_once "geoip.inc";

geoip_load_shared_mem("GeoIP.dat");
$gi = geoip_open("GeoIP.dat", GEOIP_SHARED_MEMORY);
echo geoip_country_code_by_name($gi, "php.net"), "\n";
geoip_close($gi);

Both the geoip extension and geoip library cannot be used interchangeably. The extension is newer and more update-to-date. If you need a quick IP-to-country lookup but no root access to your machine, just use the library.

Extract Hyperlinks Using Python and PHP

Is always a great fun if you can rewrite certain code from one programming language to another. I was looking at this short snippet of Python code by unconscionable which request a page and dump certain comments links.

Sample Python code reproduced here.
import urllib2, re
headers = {'User-agent': 'I promise I\'m not doing this a lot',}
req = urllib2.Request("http://www.reddit.com/r/BuyItForLife/search?q=headphones&restrict_sr=on", None, headers)
website = urllib2.urlopen(req)

html = website.read()

links = re.findall('"((http|ftp)s?://.*?)"', html)
for i in links:
    if 'http://www.reddit.com/r/BuyItForLife/comments/' in i[0]:
        print i[0]

My rewrite using PHP using file_get_contents and stream_context_create, something new for me.
<?php

$options['http']['header'] = "User-agent: I promise I'm not doing this a lot'\r\n";
$context = stream_context_create($options);

$url  = "http://www.reddit.com/r/BuyItForLife/search?q=headphones&restrict_sr=on";
$html = file_get_contents($url, TRUE, $context);
preg_match_all('/"((http|ftp)\s?:\/\/.*?)"/i', $html, $links);
foreach ( $links[1] as $link )
{
    if ( strstr($link, 'http://www.reddit.com/r/BuyItForLife/comments') )
        echo $link, "\n";
}

Comparison of both code snippet.
  1. Regex is simpler and more readable in Python. You don’t need to escape certain character (example is forward slash /) like in PHP. API is simpler and make more sense, result are returned instead of using callback in PHP where you have two sets of array.
  2. file_get_contents() is awesome and dangerous as well for reading both offline and online file. Nothing equivalent is found in Python.
  3. Finding and matching string is way more readable in Python.

Javaism in PHP Again.

Via HN. The Java-style absurdity that slowly creeping in to PHP ecosystem. History will repeat itself again. I have this feeling that PHP will one day end up like the programming language it dethroned few years back.

Rasmus (the creator of PHP) needs to step in as the Benevolent Dictator for Life (BDFL) instead of community" voting on setting the future direction of PHP. The language itself is slowly losing its identity and its PHP-way. Stop being a poor imitator of Java.

Using GeoIP with PHP - Part 2

Continue from part 1. It seems the default php5-geoip package is unstable and core dumped on me. Let’s try the PHP Extension Community Library (PECL) installation method.

Let’s remove the existing php5-geoip package.
$ sudo apt-get --purge remove php5-geoip

Install the necessary packages for PECL installation and compilation.
$ sudo apt-get install php-pear php5-dev libgeoip-dev geoip-database

Download, compile, install, and enable the geoip extension. The tee command is to solve the sudo file permission error.
$ sudo pecl install geoip
$ echo "extension=geoip.so" | sudo tee -a /etc/php5/conf.d/geoip.ini
$ sudo service apache2 restart

Double check the geoip extension is really loaded properly
$ php -m | grep geoip
geoip
$ php -r "echo extension_loaded('geoip');"
1

Test the method that gave us core dump in Part 1. No core dump and the geoip extension is stable using PECL installation method. Why?
$ php -r "print_r(geoip_db_get_all_info());"
Array
(
    [1] => Array
        (
            [available] => 1
            [description] => GeoIP Country Edition
            [filename] => /usr/share/GeoIP/GeoIP.dat
        )
......

Weird, what the difference between default Ubuntu package and PECL? Let’s check the version.
$ apt-cache show php5-geoip | grep Version
Version: 1.0.7-8

$ pecl info geoip | grep "Release Version"
Release Version       1.0.8 (stable)

So it seems both are different version. Let’s read the latest changelog which shows us one very interesting fix.
* Fix segfault with newer geoip libraries and geoip_db_get_all_info() (bug #60066)

What is bug #60066? The reason why PHP segfault is GeoIPDBFileName is not defined. Still remember the backtrace and apport crash report title line “Title: php5 crashed with SIGSEGV in add_assoc_string_ex()” we did in Part 1. Read the fix in the Subversion.

Download the source code for php5-geoip from the Ubuntu repository.
$ apt-get source php5-geoip
$ tree -L 1 .
.
├── php-geoip-1.0.7
├── php-geoip_1.0.7-8.debian.tar.gz
├── php-geoip_1.0.7-8.dsc
└── php-geoip_1.0.7.orig.tar.gz

1 directory, 3 files

Prepare the extension for compilation but run the test cases instead.
$ cd php-geoip-1.0.7/geoip-1.0.7/
$ phpize5
$ php -f run-tests.php
ERROR: environment variable TEST_PHP_EXECUTABLE must be set to specify PHP executable!

$ whereis php
php: /usr/bin/php /usr/bin/X11/php /usr/share/php /usr/share/man/man1/php.1.gz

$ export TEST_PHP_EXECUTABLE=/usr/bin/php
$ php -f run-tests.php
......
FAILED TEST SUMMARY
---------------------------------------------------------------------
Calling geoip_db_filename() with a non-existant database type within bound. [tests/008.phpt]
Calling geoip_database_info() with a non-existant database type within bound. [tests/011.phpt]
Checking timezone info with (some) empty fields [tests/014.phpt]
......

Since we install the geoip extension using PECL, is better to run the test cases that came with that same version as well. Download the source, configure, and run tests.
$ wget http://pecl.php.net/get/geoip-1.0.8.tgz
$ tar zxvf geoip-1.0.8.tgz
$ cd geoip-1.0.8
$ phpize5
$ export TEST_PHP_EXECUTABLE=/usr/bin/php
$ php -f run-tests.php
......
FAILED TEST SUMMARY
---------------------------------------------------------------------
Checking timezone info with (some) empty fields [tests/014.phpt]
......

Using GeoIP with PHP - Part 1

For the pass few months, I noticed there seems a large number of forum spam bots scanning for loophole on something that I am working on. While we managed to capture all these IP addresses and blocked them, I was curious about the locations (countries or cities) of these IP addresses. The only way is to add country-to-IP resolver or GeoIP support. Below are the installation steps in Ubuntu 12.10.

Install the GeoIP extension and the need database (only can find IP by country)
$ sudo apt-get install php5-geoip geoip-database

Check our installation
$ php -m | grep geoip
geoip

Check the available databases.
$ php -r "print_r(geoip_db_get_all_info());"
Segmentation fault (core dumped)

However, default packages seemed to be buggy. Let’s do a backtrace.
$ strace php -r "print_r(geoip_db_get_all_info());"
......
stat("/usr/share/GeoIP/GeoIP.dat", {st_mode=S_IFREG|0644, st_size=1773423, ...}) = 0
stat("/usr/share/GeoIP/GeoIPv6.dat", {st_mode=S_IFREG|0644, st_size=1226717, ...}) = 0
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)

Unfortunately there is no core dump file. Why? No worry, let’s check the core dump default behaviour.
$ cat /proc/sys/kernel/core_pattern | /usr/share/apport/apport %p %s %c

Apport ? Yes, The automatic crash report generator in Ubuntu. Let’s read the crash reports which are located in /var/crash. Get the title or summary of the report so we can google for answer.
$ cd /var/crash
$ cat _usr_bin_php5.1000.crash | grep Title
Title: php5 crashed with SIGSEGV in add_assoc_string_ex()

Google around for the title message, no luck, nothing related to geoip extension. Back to the question, where is the core file? Let’s try checking the ulimit
$ ulimit -c
0

Ok. Let’s change that to unlimited and rerun the sample code again.
$ ulimit -c unlimited
$ ulimit -c
unlimited

$ php -r "print_r(geoip_db_get_all_info());"
$ ls -l core
-rw-r----- 1 kianmeng kianmeng 15409152 Mar  9 20:07 core

Now let’s backtrace it using gdb, the GNU debugger.
$ gdb /usr/bin/php core
(gdb) bt
#0  __strlen_sse2_pminub () at ../sysdeps/x86_64/multiarch/strlen-sse2-pminub.S:39
#1  0x00000000006bc17e in add_assoc_string_ex ()
#2  0x00007fb7f6404bda in zif_geoip_db_get_all_info () from /usr/lib/php5/20100525/geoip.so
"With Elefant, I chose to use method names with under_scores instead of camelCase. I find they substantially improve readability, and while PHP moves ever-closer to Java in its syntax, I strongly prefer the direction Python, Ruby, et al take, and find underscores better match PHP too because every function in PHP uses them. So at this point I’m not renaming everything, or worse, using aliases so both ways can be supported. Instead I’m opting out of PSR-1."
-- Johnny Broadway, emphasis mine

Javaism in PHP

What an interesting piece of code showcasing two major features in PHP namely namespacing and annotation (not really a core feature but common in those Javaism PHP frameworks). Influenced by Java and implemented "superbly" in PHP. Best decision for PHP going forward.
/**
 *@var\Doctrine\Common\Collections\Collection<\TYPO3\Blog\Domain\Model\Post>
 *@ORM\OneToMany(mappedBy="blog")
 *@ORM\OrderBy({"date"="DESC"})
 */
protected $posts;

How do you replace every characters in a string with asterisk except the first and last characters?

To be more specific, how to you obfuscate an email address partially but still make it recognizable ? An example is [email protected] becomes j******[email protected]

Regrex or preg_replace to perform a regular expressions search and replace. Inspired by a regex example.
php > $regex = "/(?<!^)\S(?!$)/";
php > echo preg_replace($regex, '.', 'johndoe'), "\n";
j.....e
php >

Break down of the regex and explanation of each part.
(?<!^)  # not the first character
\S       # matches any string but a whitespace
(?!$)    # not the last character

Both (?<!pattern) and (?!pattern) are look-behind and look-ahead assertion. Assertion are test on characters before or after the matched pattern. In our case here, we want all characters that is not in the first and last position.

More details breakdown and explanation using explain, a regular expression online tools. Result as shown:
(?lt;!  # look behind to see if there is not:
^      # the beginning of the string
)       # end of look-behind
\S     # non-whitespace (all but \n, \r, \t, \f, and " ")
(?!     # look ahead to see if there is not:
$       # before an optional \n, and the end of the string
)        # end of look-ahead

Something about PHP's SAPI

0. As usual, let's install all the necessary packages in Ubuntu 12.10 before we proceed with the example code.
$ sudo apt-get install php5-cgi php5-cli libapache2-mod-php5

1. Let's write a simple PHP script and put this file (sapi.php) in the document root (/var/www). Content as shown below.
$ cat /var/www/sapi.php 

2. Let's run this script from the console.

a) Plain old PHP binary, not through the web server.
$ php -f /var/www/sapi.php 
cli

b) Similarly but using the php5-cgi binary instead.
$ php5-cgi /var/www/sapi.php 
X-Powered-By: PHP/5.4.6-1ubuntu1.1
Content-type: text/html

cgi-fcgi

c) Again, but using curl program, a HTTP client making request to the HTTP server (Apache).
$ curl http://localhost/sapi.php
apache2handler

3. What does the result in step 2 tell us?

First, the method php_sapi_name() which will give us the type of the Server API (hence the name SAPI) used by the PHP binary. Think SAPI like a plugin module with different abstraction layers for different type of APIs. Second, an explanation of each SAPI layers in step 2.

2a - PHP standalone interpreter itself.

2b - Common Gateway Interface (CGI). A standard way of a HTTP server to delegate content to a program. In this case the PHP interpreter. Compare to 2a, this interface do pass extra environment variables to the PHP program.

2c - mod_php where the PHP interpreter is embedded as module in Apache web server. Similarly to CGI, both are the only two common communications between Apache and PHP. As mentioned, the main different is CGI delegate PHP script to an external binary where for mod_php, it was passed to Apache itself.

Another way to test this out is to get the phpinfo() result by repeating the step 2. Result obtained will be quite different.

4. Why I am writing about this?

I was trying to write a console script to extract Zend Optimizer+ statistics result but the result will not be the same running through plain interpreter and mod_php. Because my lack of fundamental understanding of this concept made me wasted 3 hours. Well, you have to learn the lesson the hard way somehow.

Micro-Routing Framework

Interesting question on which micro-routing frameworks for PHP in r/php. Slim, dispatch, and klein are my favourites for their simplicity and procedural approach. Aura Router looks interesting too but feels too heavy.

As I mentioned before, someone should really add the missing routing functions to the PHP core. Thus, making PHP a fully-featured micro-framework with PDO as model and PHP itself as view. As they said, PHP as Template Engine (PATE). Two benefits for doing so. First, we have a standard way of doing routing in PHP. Second, no dependancy on any frameworks for single file script (think apc.php) or small size app (think simple REST app).

Can someone in php-internals add this to PHP 5.6?

Opening Text Steam in PHP

I'm glad I read the documentation on fread() method. Now I understand why this method behaves in such way.

The old way (before PHP 5) of handling remote (non file) data stream. What and why is 8192 ? That is the length in byte of the chunk size, which by default is 8192 bytes.
<?php
$handle = fopen("http://www.google.com/", "rb");
$contents = '';
while (!feof($handle)) {
  $contents .= fread($handle, 8192);
}
fclose($handle);
?>

The new way (from PHP 5 onwards) without the need to specific chunk size.
<?php
$handle = fopen("http://www.google.com/", "rb");
$contents = stream_get_contents($handle);
fclose($handle);
?>