Jul 6, 2009

Analysing MySQL logs

From time to time you may get shouts from your server administrator about the load your queries put on your shared hosting account.
Several people I know have been "kicked out" without notice from shared hosting. Not a very nice feeling.
But then you move to a dedicated server, and suddenly you feel like kicking yourself out, since your server starts complaining and stops serving the users...

Time to go over your queries, add indexes and make other necessary changes to lower (or spread) the load.

But WHERE DO WE START? There are a billion different query types in our application. How do we know which one is the current bottle-neck?

MySQL logs to the rescue.

There are two main MySQL logs you should use:
1. mysqld.log - a log of ALL the queries
2. mysqld-slow.log - a log of queries that took more then x seconds to run.

These logs tend to fill up really quickly..

Your hava-amina (first thought) might be to look in the slow-queries log. But in it you will find many queries that ran slowly because the server was already loaded. a problem...

To the RESCUE: MyProfi. A MySQL log analyser.

MyProfi is a command line tool that parses mysql query log and outputs statistics of most frequently used queries, sorting them by number of times they appear in a log file. The similar queries are groupped together. Thus, select id from user where login="admin" and select id from user where login='root' become select id from user where login={} - the variable parts of queries are replaced with {} markers, this make statistics analysis as easy as revewing the top of most frequently occured queries' patterns.

You can get MyProfi at: http://myprofi.sourceforge.net/

Example of its output:

Queries by type:
================
select 346 887 [84.11%]
set 29 643 [ 7.19%]
insert 23 748 [ 5.76%]
update 11 916 [ 2.89%]
execute 155 [ 0.04%]


Queries by pattern:
===================
1. 118 471 [28.73%] - select*from visitedurl where siteid={}and pagetypeid={}
2. 27 713 [ 6.72%] - set names utf8
3. 20 476 [ 4.97%] - select mimage,timage from images where id={}limit{}
4. 20 475 [ 4.96%] - select*from users where id={}

See the 28.73%? This can tell you exactly where to look and what to change. Notice that these are not actual queries, but QUERY-TYPES instead. the {} in id={} replaces various different ids that were entered.
Also notice the SET NAMES UTF8 query. This can be set in my.ini and never again be needed. (Lowering 6.72% of your query load)

Jun 30, 2009

Coding - worst practices

How NOT to code:

1. Don't mix Logic,Data and Presentation in the same file.
Example:
Notice the DB connection, the PHP codes, and the HTML all tangled...

Jun 26, 2009

Turn ON error reporting for DEBUGing

PHP usually hides many of the compiler warnings and errors.
Use the following to display errors while debuging your application:


error_reporting(E_ALL);

OR:

ini_set('error_reporting', E_ALL);


More advanced users may want to display only some of the errors.
Such as:

error_reporting(E_ALL ^ E_NOTICE);

To avoid showing notices for uninitiallized variables.

Some more options to experiment with:
E_ERROR
E_WARNING
E_PARSE
E_NOTICE
E_CORE_ERROR
E_CORE_WARNING
E_COMPILE_ERROR
E_COMPILE_WARNING
E_USER_ERROR
E_USER_WARNING
E_USER_NOTICE
E_ALL
E_STRICT
E_RECOVERABLE_ERROR
E_DEPRECATED
E_USER_DEPRECATED

Content-Types

When serving a document dynamically, you may need to tell the browser what kind of file it is.
In PHP (For JPG):

header("Content-type: image/jpeg;");


These are called mime-types.

A list of possible types:
Type Extension
application/envoy evy
application/fractals fif
application/futuresplash spl
application/hta hta
application/internet-property-stream acx
application/mac-binhex40 hqx
application/msword doc
application/msword dot
application/octet-stream *
application/octet-stream bin
application/octet-stream class
application/octet-stream dms
application/octet-stream exe
application/octet-stream lha
application/octet-stream lzh
application/oda oda
application/olescript axs
application/pdf pdf
application/pics-rules prf
application/pkcs10 p10
application/pkix-crl crl
application/postscript ai
application/postscript eps
application/postscript ps
application/rtf rtf
application/set-payment-initiation setpay
application/set-registration-initiation setreg
application/vnd.ms-excel xla
application/vnd.ms-excel xlc
application/vnd.ms-excel xlm
application/vnd.ms-excel xls
application/vnd.ms-excel xlt
application/vnd.ms-excel xlw
application/vnd.ms-outlook msg
application/vnd.ms-pkicertstore sst
application/vnd.ms-pkiseccat cat
application/vnd.ms-pkistl stl
application/vnd.ms-powerpoint pot
application/vnd.ms-powerpoint pps
application/vnd.ms-powerpoint ppt
application/vnd.ms-project mpp
application/vnd.ms-works wcm
application/vnd.ms-works wdb
application/vnd.ms-works wks
application/vnd.ms-works wps
application/winhlp hlp
application/x-bcpio bcpio
application/x-cdf cdf
application/x-compress z
application/x-compressed tgz
application/x-cpio cpio
application/x-csh csh
application/x-director dcr
application/x-director dir
application/x-director dxr
application/x-dvi dvi
application/x-gtar gtar
application/x-gzip gz
application/x-hdf hdf
application/x-internet-signup ins
application/x-internet-signup isp
application/x-iphone iii
application/x-javascript js
application/x-latex latex
application/x-msaccess mdb
application/x-mscardfile crd
application/x-msclip clp
application/x-msdownload dll
application/x-msmediaview m13
application/x-msmediaview m14
application/x-msmediaview mvb
application/x-msmetafile wmf
application/x-msmoney mny
application/x-mspublisher pub
application/x-msschedule scd
application/x-msterminal trm
application/x-mswrite wri
application/x-netcdf cdf
application/x-netcdf nc
application/x-perfmon pma
application/x-perfmon pmc
application/x-perfmon pml
application/x-perfmon pmr
application/x-perfmon pmw
application/x-pkcs12 p12
application/x-pkcs12 pfx
application/x-pkcs7-certificates p7b
application/x-pkcs7-certificates spc
application/x-pkcs7-certreqresp p7r
application/x-pkcs7-mime p7c
application/x-pkcs7-mime p7m
application/x-pkcs7-signature p7s
application/x-sh sh
application/x-shar shar
application/x-shockwave-flash swf
application/x-stuffit sit
application/x-sv4cpio sv4cpio
application/x-sv4crc sv4crc
application/x-tar tar
application/x-tcl tcl
application/x-tex tex
application/x-texinfo texi
application/x-texinfo texinfo
application/x-troff roff
application/x-troff t
application/x-troff tr
application/x-troff-man man
application/x-troff-me me
application/x-troff-ms ms
application/x-ustar ustar
application/x-wais-source src
application/x-x509-ca-cert cer
application/x-x509-ca-cert crt
application/x-x509-ca-cert der
application/ynd.ms-pkipko pko
application/zip zip
audio/basic au
audio/basic snd
audio/mid mid
audio/mid rmi
audio/mpeg mp3
audio/x-aiff aif
audio/x-aiff aifc
audio/x-aiff aiff
audio/x-mpegurl m3u
audio/x-pn-realaudio ra
audio/x-pn-realaudio ram
audio/x-wav wav
image/bmp bmp
image/cis-cod cod
image/gif gif
image/ief ief
image/jpeg jpe
image/jpeg jpeg
image/jpeg jpg
image/pipeg jfif
image/svg+xml svg
image/tiff tif
image/tiff tiff
image/x-cmu-raster ras
image/x-cmx cmx
image/x-icon ico
image/x-portable-anymap pnm
image/x-portable-bitmap pbm
image/x-portable-graymap pgm
image/x-portable-pixmap ppm
image/x-rgb rgb
image/x-xbitmap xbm
image/x-xpixmap xpm
image/x-xwindowdump xwd
message/rfc822 mht
message/rfc822 mhtml
message/rfc822 nws
text/css css
text/h323 323
text/html htm
text/html html
text/html stm
text/iuls uls
text/plain bas
text/plain c
text/plain h
text/plain txt
text/richtext rtx
text/scriptlet sct
text/tab-separated-values tsv
text/webviewhtml htt
text/x-component htc
text/x-setext etx
text/x-vcard vcf
video/mpeg mp2
video/mpeg mpa
video/mpeg mpe
video/mpeg mpeg
video/mpeg mpg
video/mpeg mpv2
video/quicktime mov
video/quicktime qt
video/x-la-asf lsf
video/x-la-asf lsx
video/x-ms-asf asf
video/x-ms-asf asr
video/x-ms-asf asx
video/x-msvideo avi
video/x-sgi-movie movie
x-world/x-vrml flr
x-world/x-vrml vrml
x-world/x-vrml wrl
x-world/x-vrml wrz
x-world/x-vrml xaf
x-world/x-vrml xof

Enable/Disable display of list of files in directory

When going to http://yoursite.com/afolder/ you may or may not wish the user to see the list of files.

Heres how to do it via the .htaccess file:

To enable directory listing:

Options +Indexes


To disable directory listing:

Options +Indexes




You can specify how to show the files.
To display icons, file sizes, etc, FANCY style:

IndexOptions +FancyIndexing


You can also hide certain files:

IndexIgnore *.gif *.jpg *.php

Jun 22, 2009

Moving a site to a different domain

Sometimes you need to move a site from one domain to another.
Happens mostly when beta testing on a temporary subdomain, and one day, you wanna move, but what will happen to all the incoming links?
There is one method for a TEMPORARY domain change [302] (for maintenance or something similar) , and there is one for a PERMANENT domain change [301].

Two good methods, via .htaccess via PHP or via HTML:

The htaccess redirection method:

redirect 301 / http://newDomain.com


For a PERMANENT redirect, or

redirect 302 / http://newDomain.com

For a TEMPORARY redirect.




The PHP redirection methods:

header('HTTP/1.1 301 Moved Permanently', true);
header('Location: http://newDomain.com/');

For a PERMANENT redirect, or

header('Location: http://newDomain.com/');

For a TEMPORARY redirect.



The HTML redirection method:

<meta http-equiv=refresh content="0; url=http://newDomain.com" />

NOTE: The 0 (Zero) can be changed to a number of seconds you'd like the browser to wait before redirecting. Usually used to display a "We have moved" notice.
NOTE2: When using 0 (zero) as the timeout param, Google/Yahoo will treat it as a 301 PERMANENT move, while when using a higher timeout duration they will treat it as a 301 TEMPORARY move.

Jun 21, 2009

Flash is hiding your menu?

Sometimes a flash SWF object will always stay ABOVE any other content.
So your nice folding menu will be inoperable.

Solution:
Add to the flash:


<param value="transparent" name="wmode" >


And in the EMBED tag:


wmode=transparent



Solution by Lior.

Jun 15, 2009

Smarty 101

The Smarty template engine - basics

NOTE: I use <{ to begin and }> to end a smarty instruction. The default installations uses just { and }. (which get confused with css) So replace them in my code if needed.

In PHP:

$name = 'Tim';

$smarty->assign('name', $name);

$smarty->display('myTemplateFile.tpl');

** Thats IT.

Inside the template ('myTemplateFile.tpl'):

<{include file="header.tpl"}>

Always include a header file. You never know when you'll need it. And yes, this is the way you include a smarty template file from another smarty template file.

Hello <{$name}>, how are you?

This is how to ECHO a variable.

<{foreach from=$myPeopleArray key=personId item=person }>

<{$personId}>. Hello <{$person.name}>.

<{/foreach}>

This is how to go over an array in smarty. The $personId (variable) and $person (array in this case) will contain a different row from $myPeopleArray each run of the FOREACH loop.

<{$nameescape:"html"}>

This is how to escape html characters from a variable inside a smarty template.

<{$shipment.pickupTimedate_format:'%A %x %H:%M'}>

Dates can also be manipulated inside smarty.

<{debug}>

This is the last command for today. Displaying all your variables and arrays so you can debug your template. All the designer ever needs is to start with this command, and see what material the developer handed to him.

These are the basics. 95% of the time you will not need anything else.

Smarty Installation

Smarty - the template engine.
Can make your life much better.

1. Download the package: http://www.smarty.net/
2. Upload it to a "/smarty" directory. (Can be below your web root, i.e. not accessible from afar)
3. Call it, in your header file:


$rootDirectory ='YOUR_ROOT_DIRECTORY';
require_once('Smarty.class.php');
$smarty = new Smarty();
$smarty->template_dir = $rootDirectory.'/smarty/projectName/templates';
$smarty->compile_dir = $rootDirectory.'/smarty/projectName/templates_c';
$smarty->cache_dir = $rootDirectory.'/smarty/projectName/cache';
$smarty->config_dir = $rootDirectory.'/smarty/projectName/configs';
$smarty->left_delimiter = '<{'; $smarty->right_delimiter = '}>';


4. Make the /templates_c directory writeable (777 is fine)

Thats it. You are go to go.

Optimization: How to time your scripts

When looking for bottle-necks in your application, you sometimes need to check how long a certain code segment runs.
Here is how to measure it:


list($usec, $sec) = explode(" ", microtime());$t1=((float)$usec + (float)$sec);
// the CODE SEGMENT goes here
list($usec, $sec) = explode(" ", microtime());$t2=((float)$usec + (float)$sec);
$time = (float)($t2-$t1);
echo $time;

Header and Footer

The importance of using Headers and Footers

Always use a header file that is require_once('myHeader.php'); from the top of every file.

Always use a header file that is require_once('myFooter.php'); from the bottom of every file.

You may leave them empty if you want, but DO put them in place. You WILL need them.

That is true for both the logic PHP side of the application, and for the presentation TEMPLATE side.

htAccess Magic

.Htaccess (Hypertext Access configuration file) can help you perform several important tasks.
Here are some examples:

AddDefaultCharset utf-8
What do you think this does? Eliminating your strange chars from appearing in non-latin languages.

Options +FollowSymlinks
RewriteEngine on
These are needed for the REWRITE section which is now coming.

RewriteCond %{THE_REQUEST} ^[^/]*/index\.php [NC]
RewriteRule . / [R=301,L]
Instead of having both http://simania.co.il/ and http://simania.co.il/index.php you will only have one. [Why this is good is another story]

RewriteCond %{http_host} ^www.simania.co.il [nc]
RewriteRule ^(.*)$ http://simania.co.il/$1 [r=301,nc]
Instead of having both http://simania.co.il/ and http://www.simania.co.il/ you will only have one. [ same note]

RewriteCond %{http_host} ^somethingOLD.simania.co.il [nc]
RewriteRule ^(.*)$ http://simania.co.il/$1 [r=301,nc]
Old subdomain that no longer exists. Make it disappear, without loosing traffic.

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} ^/(.*)/(.*)/(.*)/(.*)$
RewriteRule ^rss/([^/]*)/([^/]*)/([^/]*) /feed.php?type=$1&user=$2&item=$3 [T=application/x-httpd-php]
Have some FRIENDLY urls. From http://simania.co.il/rss/AAA/BBB/CCC you get http://simania.co.il/feed.php?type=AAA&user=BBB&item=CCC

ErrorDocument 404 /404.php
Have all the mistyped urls (and those that no longer exist) bring up your custom 404 error file.

order allow,deny
deny from 41.208.
allow from all
Block some nasty IP addresses, or allow just the ones you want.

Requirements from a web designer

Designers used to work in printshops.
Brochures were the bread and butter for them.

Web sites came along.
DYNAMIC web sites came along.

Designers (most of them) still think in static terms.

"I'll give you a PSD", they say. "Wow, thanks", I reply, "and who will do the DESIGN?"
"HA?" they reply...

Designing a dynamic web site involves more then just statically making a sketch in Photoshop.
Some areas need to be made stretchable, other areas need to have AJAX loading or other javascript effects. CSS needs to be used to perform various functions, and ofcourse browser dependance need to be addressed.
These are all part of the DESIGN. You can't escape it. It's a brave new world out there.

Idealy, a designer would get the list of variables and create a full template (in Smarty or other engine) to bring the site to life. Nothing short of that.

User Interface design is needed, one that will serve many users, not a flat one-time mailbox brochure that will later serve as a pizza tray.

Three layers of seperation

Data, Logic and Presentation

When building an application(i.e. something) in PHP it is very easy to fall into the pit of putting everything in one big file.
Usually starting with a database connection:

$connection = mysql_connect("localhost", "USER", "PASSWORD");
mysql_select_db("DATABASE", $connection);

$result = mysql_query('SELECT * FROM people');
$row = mysql_fetch_assoc($result);

continue with some logic:

$people = array('Joe', 'Marry', 'Tim', $row['personName']);

and put some presentation:

echo 'Hello'.$people[0];

Then some more data, and more logic and more presentation.
All in one big mess.

So, how do we clean this mess? Using the three layers of seperation.
DATA belongs in one(or more) file(usually a class).
LOGIC belongs in a different file(usually also a class).
PRESENTATION belongs in a template of some kind.

Suggestion
Start your file with a:

require_once("MyData.class.php");
$oData = new Data;
require_once("MyLogic.class.php");
$oMyLogic= new MyLogic;

require_once("MyPresentation.class.php");
$oMyPresentation = new MyPresentation;

Continue with:

$theData = $oData->getTheData();
$theImprovedData = $oMyLogic->doTheMath($theData);
$oMyPresentation->doThePresentation($theImprovedData);


Benefits:
The Designer (see post about him later) can mess around with his design without disturbing the programmer. If there is a bug, it is simple to see whose job it is to fix it.
Managing you application is much easier.
Reusing code is doable.
UpScaling your application is doable.

Recommended tool of trade:
SMARTY (A PHP template engine):
http://www.smarty.net/