- Posts tagged PHP
- Explore PHP on posterous
PHP's World Of Arrays
Arrays in PHP are quite powerful, partly because they are not actually arrays (read on for an explanation), but can be treated as such when needed. They gain most of the utility from a vast library of built in helper functions associated with them.
Much of my day is spent looking at others code, (were ‘others’ does include ‘me in the past’), and I often see arrays under utilized or code that fights arrays by implementing foreach loops where a single function call would suffice. With some review of the functionality afforded arrays in PHP you can learn to use them more effectively and realize that they may very well be the best solution in circumstances you had not thought of before. This is nothing against Object Oriented Programming, as I consider myself a OO programmer. There is just quite a bit that can be done efficiently and elegantly with plain old arrays in PHP.
So as a refresher course for myself and hopefully to show others some array functionality they were not aware existed, I’ve decided to write a few blog posts on some things I find useful (and have newly discovered after re-reading the array docs).
This being the first of those posts, I’ll start with the basics, a very quick intro to just what an array is and then cover examples of using arrays as some of the more simple data structures in computer science: Stacks and Queues.
What Is An Array In PHP?
What is referred to as an ‘array’ in PHP is actually an ordered map. The keys of an array can be either an integer or a string. The value for an array element can be anything.
Arrays can be created using the array() construct or in a more literal fashion of using brackets ([ ])
$x = array('bob'); $x = array(0 => 'bob'); $x[] = 'bob'; $x[0] = 'bob';
All the examples above will result in this array:
array(0 => 'bob')
If a key is not specified for a value, a new key is created with the value of 1 + the current max of the integer keys in the array.
$y = array(0 => 'red', 1 => 'blue', 7 => 'green'); $y[] = 'brown';
The $y array would now be:
$y = array(0 => 'red', 1 => 'blue', 7 => 'green', 8 => 'brown');
For more of the basics of PHP arrays, there is an excellent php.net page devoted to that subject.
Using Arrays For Basic Data Structures
Stacks
In computer science, a Stack is a last in, first out (LIFO) structure.
>push pop>
\ /
X
X
X
X
XAn example of a Stack is your browser history. You click a link and it is pushed onto the top of your browser history. You continue to click links and they are continually pushed onto the top of that Stack. Then when you click on the ‘back’ button, the very top link is popped of your history Stack.
In PHP the functions array_push and array_pop are used for manipulating an array as a Stack.
$browser_history = array('https://mail.google.com', 'http://www.php.net' ); array_push($browser_history, 'http://www.topgear.com/uk/'); print_r($browser_history); // Array // ( // [0] => https://mail.google.com // [1] => http://www.php.net // [2] => http://www.topgear.com/uk/ // ) $site = array_pop($browser_history); echo "site: {$site}"; // site: http://www.topgear.com/uk/ print_r($browser_history); // Array // ( // [0] => https://mail.google.com // [1] => http://www.php.net // )
Note that in PHP, rather than using array_push, you can just use bracketed syntax which has the same effect.
array_push($array, 'value') // has the same effect as $array[] = 'value';
Queues
A Queue is a First-In-First-Out (FIFO) data structure. (think conveyor belt)
enqueue dequeue
(unshift) queue (shift)
X --> XXXXXXX --> XIn PHP, you can use an array as a Queue by utilizing array_unshift to prepend and element to the beginning of an array and then array_pop to take an element off the end of the same array.
An example would be any perishable items in your grocery store’s dairy case. As items come into the store they are loaded in the back of the case and customers select items for purchase from the front of the case.
$yogurts = array('exp:05/10/2011', 'exp:05/08/2011' ); print_r($yogurts); //Array //( // [0] => exp:05/10/2011 // [1] => exp:05/08/2011 //) array_unshift($yogurts, 'exp:05/13/2011', 'exp:05/12/2011'); print_r($yogurts); //Array //( // [0] => exp:05/13/2011 // [1] => exp:05/12/2011 // [2] => exp:05/10/2011 // [3] => exp:05/08/2011 //)
Note, these methods do not return the affected array so you wouldn’t normally do:
$yogurts = array_unshift($yogurts, 'exp:05/13/2011', 'exp:05/12/2011');
as array_pop simply returns the last value of the array and array_unshift returns the new number of elements in the array.
So that is it for now, next up I’ll discuss using the various function to calculate the differences and intersections between array.
PHP print_r as valid PHP
If you ever have PHP print_r output that you just want to cut/paste as PHP code.
class Arr { /** * $array Can be either an Array or the string output of * print_r($array, true); */ public static function print_php($array) { $array = is_array($array)?print_r($array,true):$array; $array = preg_replace( array( '/Array\n/', '/\[(.*)\] =>/', '/\)\n/' ), array( "array\n", '"${1}" =>', "),\n" ), $array); // need regex skill++ , for now this will do $array = preg_replace_callback( '/=> (.*?)\n/', // only replace if it is not the word 'array' or just digits create_function( '$matches', '$match = isset($matches[1])?$matches[1]:null; $qt = ctype_digit($match)||$match=="array"?"":"\""; $c = $match=="array"?"":","; return "=> {$qt}{$match}{$qt}{$c}\n";' ), $array); return $array; } }
Using Unicode To Increase Information Density in Tweets
Quite a while back I grabbed the twitter handle @pdxweather with plans to broadcast the local weather over it. I first thought I would send out a daily broadcast for today's weather and tomorrow. Being Portland, Oregon, I'm centering around the "Chance of Rain" for those days at least as a starting point. This has proven to be quite a challenge to accomplish with 140 characters. The technology needed to produce such tweets is not all that difficult. I built a little PHP script that would parse the forecasts from form the weather.gov API. I then have a PHP script that builds a short summary of that information and tweets it (once a day at this point). http://twitter.com/pdxweather
Attempt 1:
Sun_18th:light rain precip%day:13 precip%eve:29 Mon_19th:light rain precip%day:53 precip%eve:64 (NOAA splits the % chance of rain to day and eve. I like this feature so I want to have that in the tweets also even though it makes it that much more difficult to stay under 140.) Lots of room for improvement here.
- Hard to see the dividing line between the days
- Not even showing hi/low temps yet and we are at ~95 char so longer weather descriptions (i.e. "Light rain and high wind warning"") along with temps could easily put us over 140
- Overall, it's just hard to parse out the individual bits of information
Attempt 2:
Goals:
- Reduce the overall character count of what we have so far so we can add more info.
- Make the tweet more 'human brain parse-able'
I first trimmed the day descriptions to gain some more characters.
Sun18:light rain precip%day:13 precip%eve:29 Mon19:light rain precip%day:53 precip%eve:64
I then determined correct spelling was optional and substituted lite for light (lite seemed a better solution than lght or lt)
Sun18:lite rain precip%day:13 precip%eve:29 Mon19:lite rain precip%day:53 precip%eve:64
These helped on the character count, but you could easily argue that these make the tweet slightly less readable. What we really need is something that shortens the character count and at the same time increases its readability. For this I turned to Unicode. If I could find a single character to replace a word like 'Sunny' or 'Rain', I could regain many characters to use elsewhere in the Tweet. I did find some 'weather' glyphs in a miscellaneous section of Unicode, unfortunately most seem to render into illegible blobs because of the typical small size you see them at. I did find
- sun:☼
- snow:✽
but nothing good for rain that was legible at small sizes (does this look like rain on an umbrella? ☔).
So I started scanning the Unicode field for something that 'looked' like rain and settled on ⑊. So using ⑊ for rain, we are at:
Sun18:lite ⑊ precip%day:13 precip%eve:29 Mon19:lite ⑊ precip%day:53 precip%eve:64
I then did a major refactor to the order of things and dropped some 'not completely necessary' terms:
Sun18:lite ⑊ 13%day 29%eve Mon19:lite ⑊ 53%day 64%eve
At this point, a great deal of ground has been made on character count, down to 53 characters, or about a 45% reduction. As a final step, I rely on alpha/digit/symbol boundaries and remove space between them. In an effort to emphasize boundaries, it is back to Unicode with → and ▮. So here it is at 49 chars:
Sun18 lite⑊13%day→29%eve▮Mon19 lite⑊53%day→64%eve
Original at 95
Sun_18th:light rain precip%day:13 precip%eve:29 Mon_19th:light rain precip%day:53 precip%eve:64
Now What
The goal now it to allow this logic to all weather tweets with will involve building a NOAA weather speak to Tweet Weather speak translator. So the overall architecture will be
- nightly, hit the NOAA API and and parse/cache the forecast on the local server
- once a day (or more), use that cached data to tweet the forcast
So I'm off to finish that, the starting point is here on github. I'll document and cleanup that code as I go along Also looking for feedback on the compaction techniques I'm using for the Tweets, so please comment if you have suggestions
10 Minutes to a Leaner LAMP stack
The Setup
Assumptions: You have root on the server in question or you at least have enough server access to effect the configuration of Apache and MySQL.The test server setup:
- A Virtual Private server running on Rackspace cloud
- Ubuntu 9.04 (Jaunty Jackalope)
$ sudo apt-get update $ sudo apt-get upgrade $ sudo locale-gen en_US.UTF-8 $ sudo apt-get install apache2-mpm-prefork php5 php5-dev mysql-server-5.0 mysql-client-5.0 php5-mysql $ sudo a2enmod rewrite
- Installed latest Wordpress and added some test posts
Baseline Performance:
Before you start changing anything be sure to record the baseline performance ot the server. Place the server under load. I used http_load but anything similar can be usedThe Test URL's that http_load will draw from
$ cat pdxphp-test http://67.23.47.195/ http://67.23.47.195/2010/02/test-post-1/ http://67.23.47.195/2010/02/test-post-2/ http://67.23.47.195/2010/02/test-post-3/ http://67.23.47.195/2010/02/test-post-4/ http://67.23.47.195/2010/02/test-post-5/
Run the test
$ http_load -parallel 5 -seconds 20 pdxphp-test 83 fetches, 5 max parallel, 1.74373e+06 bytes, in 20.0009 seconds 21008.8 mean bytes/connection 4.14982 fetches/sec, 87182.7 bytes/sec msecs/connect: 80.6013 mean, 99.26 max, 71.974 min msecs/first-response: 795.394 mean, 5495.6 max, 225.29 min HTTP response codes: code 200 -- 82
Apache
Reduce the number of modules loaded
You can start with this. It will typically not give you incredible results but you will save some resource and it is a good security policy. You can list your loaded modules withapache2ctl -t -D DUMP_MODULES
Loaded Modules: core_module (static) log_config_module (static) logio_module (static) mpm_prefork_module (static) http_module (static) so_module (static) alias_module (shared) auth_basic_module (shared) authn_file_module (shared) authz_default_module (shared) authz_groupfile_module (shared) authz_host_module (shared) authz_user_module (shared) autoindex_module (shared) cgi_module (shared) deflate_module (shared) dir_module (shared) env_module (shared) mime_module (shared) negotiation_module (shared) php5_module (shared) rewrite_module (shared) setenvif_module (shared) status_module (shared)
$ sudo a2dismod cgi Module cgi disabled. Run '/etc/init.d/apache2 restart' to activate new configuration! sam@pdx-test:/etc/apache2/mods-enabled$ sudo apache2ctl start
Turn off htaccess
Explanation from Apache. So all you need to do is take the contents of the .htaccess file in your site's webroot and place that in the corresponding vhost. Then turn off htaccess files with AllowOverride None and rm the .htaccess file in the web root after restarting apache.sudo vi /etc/apache/sites-enabled/wordpress
rm /var/www/wordpress/.htaccess
Now, how to really affect apache
This is all well and good and Apache will be better off for it but if you had a server that was paging and dying under load, after making these changes, that will probably not change. The bigger issue shown in the top output above is that, for the amount of physical RAM, there are just too many 20+MB processes the apache conf file controls these settings (/etc/apache2/apache2.conf on Ubuntu) The stock settings:<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestsPerChild 0
</IfModule><IfModule mpm_prefork_module>
StartServers 1
MinSpareServers 1
MaxSpareServers 5
MaxClients 5
MaxRequestsPerChild 1000
</IfModule>The Results thus far
[caption id="attachment_332" align="alignnone" width="651" caption="Top output with Apache Trimmed and under load"] [/caption]MySQL
Now onto MySQL. We saw above that MySQL is staring up and grabbing ~21M of RAM. A low to medium volume LAMP server probably doesn't need all that but, again every situation is different. Here though are some notes of how to tune the Low Hanging Fruit of MySQLIf you don't use it, Turn it off
Same as with Apache modules, turn off what you do not need. Storage engines are a great place to start. Very few frameworks (including WP), utilize InnoDB by default. Most use good old MyISAM. Stopping MySQl from loading the InnoDb engine (and its predecessor:bdb) is quite simple, the lines are in my.cnf, just uncomment themskip-innodb skip-bdb
# used for holding built indexes key_buffer = 16M # largest query that is cache-able query_cache_limit = 1M # used for caching queries query_cache_size = 16M
# used for holding built indexes key_buffer = 4M # largest query that is cache-able query_cache_limit = 500K # used for caching queries query_cache_size = 8M
mysql> SHOW STATUS WHERE Variable_name LIKE 'Key_blocks_%' OR Variable_name LIKE 'Qcache_%'; +-------------------------+----------+ | Variable_name | Value | +-------------------------+----------+ | Key_blocks_not_flushed | 0 | | Key_blocks_unused | 13369 | | Key_blocks_used | 27 | | Qcache_free_blocks | 4 | | Qcache_free_memory | 16326632 | | Qcache_hits | 5969 | | Qcache_inserts | 95 | | Qcache_lowmem_prunes | 0 | | Qcache_not_cached | 410 | | Qcache_queries_in_cache | 46 | | Qcache_total_blocks | 106 | +-------------------------+----------+ 11 rows in set (0.00 sec)
The Final result of our tinkering
So now that we have trimmed Apache and MySQL lets see what the top output looks like with the server under load Our CPU load has reduced (idle is up to ~65%). More importantly we are no longer paging and we still have a bit of RAM left over. MySQL is running with ~8M of RAM, down from ~21M. Also as seen below, we've roughly doubled our performance. Up to 6.85 req/sec and first response in down to 276ms.$ http_load-parallel 5 -seconds 20 pdxphp-test 137 fetches, 5 max parallel, 4.69493e+06 bytes, in 20 seconds 34269.6 mean bytes/connection 6.85 fetches/sec, 234747 bytes/sec msecs/connect: 80.6284 mean, 96.353 max, 73.043 min msecs/first-response: 276.766 mean, 447.707 max, 225.995 min HTTP response codes: code 200 -- 137
Links:
Your First PHP Development Environment
- ease of install and use for someone new to all this technology
- cross platform versions available for Windows and Linux flavors including OS X
- extensibility In particular, Firefox and Netbeans. As the user grows comfortable with these tools, they will discover that they contain many features to aid in web development. (firefox: firebug, web-dev toolbar netbeans: integrated source control, xdebug, etc)
Firefox
Install
Get the files from: Install the firebug addon : http://getfirebug.com/XAMPP
Install on Windows (windows 7 64bit edition shown)
Get the files from: XAMPP should do this by default, but be sure to install at C:\ In service section check-
Install apache as service
-
Install mysql as service
Netbeans Editor
Configure after Install
Apply Updates
[caption id="attachment_279" align="alignnone" width="638" caption="Go to Help > Check For Updates"] [/caption]Test
Now create a new PHP application project called {YOUR NAME}-week1 Place the project in the XAMPP htdocs folder Confirm the URL your project will be found at. (In our case, Netbeans should make the right guess here, so just confirm and click 'Finish'Editor Will Open and Netbeans will automatically create a starter index.php file for you
Clean up some unneeded windows
close these windows (you can always get them back later if you like)-
navigator
-
files
-
services
-
palette
Now to make a few edits and create a new file so we can start to get familiar with the IDE.
Add some PHP See the file in a browser by clicking the green Play (>) button on the toolbar. The Browser should open at the URL for the file. create another file called new-file.php- Menu: File > New File
- Choose category PHP, File Type PHP Web Page
- Next
- Change the filename to new-file.php
- Finnish
Portland Restaurant Health Map
Get the data
I searched around the web and found the Multnomah County Food Establishment Inspections Search. I made an attempt to get an export of the back-end data for this by calling county health. They were helpful but when I received the export of the data it was just the business records, not the inspection records for the businesses. I think they may have just misunderstood me and I probably could have pressed more and gotten data I needed, but I thought it would be fun the polish the old web scraping skills instead. Also, a scraping strategy would allow me to refresh the data whenever needed and I wouldn’t have to keep bugging MCHD. Selenium is a suite of web app testing tools. Selenium IDE is a firefox addon that records all the actions you take in the browser. Meant for building functional testing scripts but doubles as a great web scrape script building tool. What I find most useful about Selenium IDE is that after recording your script you can export it to the xUnit version of your choice, PHPUnit in my case. This gives you the starting point for your script and you can then add things like database persistence for the information you are scraping and utilize the phpUnit assertion methods to let you know if your script has broken. Then, you can use a tool called Selenium Remote Control to re-run the script (and drive the browser) anytime you need. This intro video does a great job of explaining some of Selenium’s features. [caption id="attachment_94" align="aligncenter" width="600" caption="Selenium Script Churning Through Data"] [/caption] So I needed to accomplish 4 things. (I included links to the scripts I used, these are by no means ‘production ready’ but some might find them useful as a starting point to their own projects. Also here is the DB sql used.)Step I: Pull the establishment records from the MCHD site
I noticed that on the MCHD site, if you just clicked ’search’ without any criteria you were taken to a holistic, paginated set of the records (currently 130 pages for total of just over 3000 records). So my first script was started with selenium IDE and worked through these 130 pages, gathering establishment meta-data and storing it in a mysql database. The ScriptStep II: Pull the inspection scores for the gathered establishments from the MCHD site.
This was done by again, using Selenium IDE to start a PHPUnit script that scraped the inspection record for each gathered establishment. It simply queries all the establishment ids from out database and builds URLs to scrape the inspection data for each business and store that information in an inspections table in the database. The ScriptStep III: Geocode the Establishment Records using Google
In preparation for displaying the data on a map, I needed to get the lat/long for each establishment in the database. I did this using Google’s Geocode service but there are many options for services that can accomplish this. Just be sure you stay within their Terms Of Use. The ScriptStep IV: Display the Establishments on something akin to a heat-map
This is the easy part once you’ve done the heavy lifting in steps I,II and III. It involves one query from the Db to pull the score, latitude, and longitude for each establishment we know about. Then using a fairly simple php web page we build the HTML and javascript to display this data on a Google map. The ScriptAugmenting Web Services with SMS and XMPP
A project called Extapi, is a small web app that manages this coordination between multiple channels and services.
here are the slides for my presentation given on November 14th 2008 at PHP|Works
AT PHP Works
Listening to the Keynote from Kevin Dangoor (founder of turbo gears). He's discussing successfully fostering open source projects.
Looking forward to meeting new folks with PHP and/or Python backgrounds

