Serious PHP, part 1
I used PHP 3 a lot back in the day, and I built some seriously interesting stuff with PHP 4 before moving on to what was then consider more “serious” technology. Recently I’ve been looking at PHP again, just to figure out how the famous LAMP stack works these days. Care to follow along?
In the below I assume you’re on Mac OS X and you sort-of know your way around unix.
Installing a bunch of packages under Mac OS X
We’re going to use a whole bunch of stuff…let’s get the package in one go (hint: you can install multiple ports at a time, see
- Install MacPorts
- Install apache2:
sudo port install apache2
- Install MySQL 5:
sudo port install mysql5
(You will need to follow some on-screen instructions to finish configuration)
- Install SQLite:
sudo port install sqlite3
- Install Perl 5.8:
sudo port install perl5.8
- Install Apache-Test:
sudo port install p5-apache-test
- Install PHP 5:
sudo port install php5 +apache2+mysql5+pear+sqlite(you may want to add some more options, see what’s available using
port variants php5; You may also need to follow some on-screen instructions to enable the extension within apache)
sudo cp /opt/local/etc/php.ini-recommended /opt/local/etc/php.ini
- Configure pear:
sudo pear config-set php_ini /opt/local/etc/php.ini
sudo pear upgrade-all
sudo pear channel-update pear.php.net
sudo pear channel-update pecl.php.net
- Install APC:
sudo pear install APC
- Install Memcached:
sudo port install memcached
- Install memcache for python:
sudo port install php5-memcache
(You will need to follow some on-screen instructions to enable the extension)
Setting up MySQL replication
MySQL replication is a technique that helps with scaling up your application. Sooner or later your database tends to become a bottleneck, and in that case what you do is make sure your
SELECT statements go to database slaves. It is easier to get this right from the start, rather than re-write your application later. So, set up some replication locally…Buy and read High Performance MySQL to get a good grasp for the details; it’s the best book on the subject.
After you’ve RTFMed a bunch, assuming you have a basic mysql install set up…here’s the magic…
# set the root password mysqladmin -u root password 'blaat' # shortcut my="mysql -uroot -pblaat" # db we'll be using echo "DROP DATABASE IF EXISTS test;" | $my echo "CREATE DATABASE test;" | $my echo "GRANT ALL ON test.* TO 'test'@'%' IDENTIFIED BY 'test'" | $my # prep for replication echo "GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'%' IDENTIFIED BY 'blaat'" | $my # I always manage to forget this one... echo "FLUSH PRIVILEGES;" | $my # enable binary logging and set server-id on to-be-master sudo cat > /opt/local/etc/mysql5/my.cnf <<END [mysqld] log-bin server-id = 1 END # create config for first slave to run on port 3307 sudo cat > /opt/local/etc/mysql5/my_3307.cnf <<END [mysqld] server-id = 2 master-host = 127.0.0.1 master-user = repl master-password = blaat master-port = 3306 port = 3307 socket = /opt/local/var/run/mysql5/mysqld_3307.sock pid-file = /opt/local/var/db/mysql5_3307/my.pid datadir = /opt/local/var/db/mysql5_3307 log-error = /opt/local/var/db/mysql5_3307/my.error.log END # create config for second slave to run on port 3308 sudo cat > /opt/local/etc/mysql5/my_3307.cnf <<END [mysqld] server-id = 2 master-host = 127.0.0.1 master-user = repl master-password = blaat master-port = 3306 port = 3308 socket = /opt/local/var/run/mysql5/mysqld_3308.sock pid-file = /opt/local/var/db/mysql5_3308/my.pid datadir = /opt/local/var/db/mysql5_3308 log-error = /opt/local/var/db/mysql5_3308/my.error.log END # stop the current mysql database sudo killall mysqld_safe # remove any previous/old binary log files rm /opt/local/var/db/mysql5/*-bin* # initialize data directories for the slaves mkdir /opt/local/var/db/mysql5_3307 chown mysql:mysql /opt/local/var/db/mysql5_3307 rsync -av /opt/local/var/db/mysql5/ /opt/local/var/db/mysql5_3307/ mkdir /opt/local/var/db/mysql5_3308 chown mysql:mysql /opt/local/var/db/mysql5_3308 rsync -av /opt/local/var/db/mysql5/ /opt/local/var/db/mysql5_3308/
Pfoeey. Let’s see if that worked (save the below to a script file):
#!/usr/bin/env bash # starts 3 mysql servers sudo mysqld_safe >/opt/local/var/db/mysql5/my.out 2>&1 & sudo mysqld_safe --defaults-file=/opt/local/etc/mysql5/my_3307.cnf \ >/opt/local/var/db/mysql5_3307/my.out 2>&1 & sudo mysqld_safe --defaults-file=/opt/local/etc/mysql5/my_3308.cnf \ >/opt/local/var/db/mysql5_3308/my.out 2>&1 &
Let’s see if we got replication going:
echo "CREATE TABLE repl_test ( id int(11) PRIMARY KEY );" \ | $my test tail /opt/local/var/db/mysql5_3307/my.error.log tail /opt/local/var/db/mysql5_3308/my.error.log
Setting up Memcached
Memcached needs essentially no setup. Try this (save the below to a script file):
#!/usr/bin/env bash # starts 2 memcached servers hostname=127.0.0.1 memperdaemon=128 daemonport1=11211 daemonport2=11212 memcached -d -l $hostname -m $memperdaemon -p $daemonport1 memcached -d -l $hostname -m $memperdaemon -p $daemonport2
Setting up Apache to use virtual hosting
We’ll have apache listen on a separate port where our app can be all by itself without getting disturbed by your other dev projects that invade its URL space.
look for the line
and un-comment it.
- Then change that file:
sudo cat >/opt/local/apache2/conf/extra/httpd-vhosts.conf <<END NameVirtualHost *:80 <VirtualHost *:80> DocumentRoot "/opt/local/apache2/htdocs" </VirtualHost> Listen 8810 NameVirtualHost *:8810 <VirtualHost *:8810> ServerName localhost:8810 DocumentRoot $HOME/doodle/htdocs <Directory "$HOME/doodle/htdocs"> Options Indexes FollowSymLinks AllowOverride None Order allow,deny Allow from all </Directory> </VirtualHost>
- Test the config:
sudo /opt/local/apache2/bin/apachectl configtest
then start (restart if started)
sudo /opt/local/apache2/bin/apachectl stop
sudo /opt/local/apache2/bin/apachectl start
Make pecl/filter more pendantic
This is a pretty awkward PHP extension that implements user-submitted variable sanitization rather efficiently. Take cross-site scripting seriously, and protect against it!
look for the line
filter.default = "special_chars"
filter.flags = FILTER_FLAG_ENCODE_HIGH
- Restart apache.
When are we going to do any PHP?
Let’s see if part 2 has more actual PHP in it. The above list of dependencies should give you some idea of where I’m going🙂. For now try this:
cat > ~/doodle/htdocs/phpinfo.php <<END <?php phpinfo(); ?> END open http://localhost:8810/phpinfo.php