Friday, February 5, 2010
practice tests for zend php 5 certfication
4 exam practice online test for "Zend PHP 5 Certification", GBP 10.
description
http://shop.zend.com/eu/php-certification/zend-php-certification-online-practice-testing.html
contact me at elvisciotti [at] gmail (dot) com, payment through paypal
Thursday, February 4, 2010
PHP and scalability
It has been the butt of criticism as considered not scalable: totally wrong !
A system is scalable when is able to keep the performances under an increased load, mainly due to more users. Speaking about scripting execution velocity (that is a constant in that evaluation) is a completely different kettle of fish.
So, PHP, Python and Perl absolutely scale as J2EE/.NET if the server is upgraded or more parallel servers are added.
Note that all the session-related problems (sticky sessions etc..) are managed in a lower layer, so PHP has no problem with that.

An interesting book about scalability is :Building Scalable Web Sites - written by Cal Henderson, the chief software architect of Flickr (built with PHP)
Saturday, January 30, 2010
Who reads this blog ?
It's rather foreseeable to see which are the countries more interested in a technical blog.
I'm only surprised to see no visits from China and Norway, as well as same number of visitors from Spain and Ukraine and Romania.

To obtain a better paid job I'm really thinking about moving to Madagascar :D
PHP for file moving / managing
Example
Here is a simple script I'm using to copy the latest mp3 files from a directory to another one (ipod shuffle) skipping the already existing files. Basically it's a kind of one-way-sync script for files filtered by mask and creation date. (To run it from the command line, launch it from the destination directory. e.g.: "php -f script.php" in the root of the ipod, or any USB MP3 player)
define('_SOURCE_PATH_', 'd:/documents/Music/incoming/');
define('_DEST_FOLDER_' , 'Music/'); #ipod shuffle
foreach (new DirectoryIterator(_SOURCE_PATH_) as $f) {
if ( Utils::is_recent_mp3( $f->getPathname() ) &&
Utils::copy_if_not_exists( $f->getPathname(), _DEST_FOLDER_.$f->getFilename() )
)
echo "[COPIED][{$f->getFilename()}]\n";
}
class Utils {
public static function is_recent_mp3($path, $daysOld = 7) {
return ( substr($path,-1)=='3' && filemtime($path) > ( time()-$daysOld*24*3600) );
}
public static function copy_if_not_exists($from, $to){
return ( file_exists($from) && !file_exists($to) ) ? copy($from, $to) : false;
}
}
Tuesday, January 26, 2010
Simple PHP script to edit front end components
Solution
A MySQL database is not needed, saving to files is much more appropriate for these requirements. Also SQLite is not necessary, as we just want to do only basic operations.
To do it, I've used one of my scripts that meets all of those requirements using only one file (the script, to place in any position, better a separate "admin" folder) + a config file (basic options: array with the list of the frontend component and their relative paths, user and password to login) + FCK editor files.
The script (protected with a simple session control + form to login) basically lists the components and allows to click on them and change the text inside using FCK editor (free WYSIWYG html editor). Also a simple backup system is provided, by keeping/restoring the previous version saved.
It's quite easy to implement a script like that.
To whom may be interested in my version (<200 LOC, made long time ago, so PHP4 compliant), let me know.
Wednesday, January 20, 2010
My Zend Certification
90 tech questions, some of them answerable only by reading some books, some others by knowing the exact behaviour and arguments of PHP5 functions and settings (quite a lot of stuff to remember considering also XML, PDO, STD lib,streams and filters), some other only with work experience, some of them with a code/algorithm comprehension ability and deep OOP skills.
It will may be more useful than my master's degree in my CV :)
Curiosity: how many certified engineer PHP5 are there at the moment in :
Germany: 338, UK: 251, France:222, Italy:53, Spain: 40, Ireland:35
USA:746, India:128, Canada: 114, China: 28
Thursday, January 14, 2010
PDO example
try {
$pdo = new PDO("mysql:host=127.0.0.1;dbname=dev;","root","" );
#$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$pdo->exec("DELETE FROM `User` WHERE id<>293968 ");
#insert
$insertedRows = $pdo->exec("INSERT INTO `User` (username, password) VALUES ('elvis','ciotti') ");
$lastInsertId = $pdo->lastInsertId();
echo "Inserted $insertedRows rows [id = $lastInsertId]\n";
$pdo->exec("DELETE FROM `User` WHERE id=$lastInsertId ");
#fetch
foreach ($pdo->query("SELECT * FROM `User` ", PDO::FETCH_ASSOC) as $row){
echo "{$row['id']}:{$row['username']}\n";
}
#insert con statement ":"
$stmt = $pdo->prepare("INSERT INTO `User` (username, password) VALUES (:username, :password) ");
$stmt->bindParam(':username',$user);
$stmt->bindParam(':password',$pass);
#
$user='aaaa'; $pass='aa'; $stmt->execute();
$user='bbbb'; $pass='bb'; $stmt->execute();
#insert con statement "?"
$stmt = $pdo->prepare("INSERT INTO `User` (username, password) VALUES (?, ?) ");
$stmt->bindParam(1,$user);
$stmt->bindParam(2,$pass);
#
$user='cccc'; $pass='cc'; $stmt->execute();
$user='dddd'; $pass='dd'; $stmt->execute();
#insert con execute ":"
$stmt = $pdo->prepare("INSERT INTO `User` (username, password) VALUES (:username, :password) ");
$stmt->execute(array(":username"=>"eeee",":password"=>"ee"));
#insert con execute "?"
$stmt = $pdo->prepare("INSERT INTO `User` (username, password) VALUES (?, ?) ");
$stmt->execute(array("ffff","ff"));
#fixed val, no vars
$stmt->bindValue(1,"gggg");
$stmt->bindValue(2,"gg");
$stmt->execute();
$stmpt_all = $pdo->prepare("SELECT * FROM `User` LIMIT 10");
$stmpt_all->execute();
#echo "all: ".print_r($stmpt_all->fetchAll(),1);
$stmpt_all = $pdo->prepare("SELECT id, username, password FROM `User` LIMIT 10");
$stmpt_all->bindColumn(1,$id);
$stmpt_all->bindColumn(2,$user);
$stmpt_all->bindColumn(3,$pass);
$stmpt_all->execute();
echo "fetch: {$stmpt_all->rowCount()} rows: \n";
while($row = $stmpt_all->fetch(PDO::FETCH_BOUND)) { #foreach
echo " [$id][$user][$pass]\n";
}
} catch (PDOException $e){
echo $e->getMessage();
}
?>
Saturday, December 19, 2009
PHP Arrays sort
There are lots of PHP defined function to order arrays (the core of PHP, technically are hashmaps), ordering by value or keys, preserving key order or not, using an user-defined function, normal or reverse order, etc...
Following, some clear example of the main ones, and some tips about how to remember them
ORDER BY VALUE
sort(): order by VALUE (keys destroyed and renumberted starting from zero)
$a = array('z'=>'A', 'y'=>'C','k'=>'B','x'=>'B');
sort( $a ); # Array ( A ,B ,B ,C )
asort(): as the previous, but it maintains index association
$a = array('z'=>'A', 'y'=>'C','k'=>'B','x'=>'B');
asort( $a ); # Array ( [z] => A , [k] => B , [x] => B , [y] => C )
natsort(): use "natural" sorting
$a = array('z'=>'5p', 'y'=>'10p','20p');
sort( $a ); # Array ( 10p ,20p ,5p )
natsort( $a ); # Array ( [2] => 5p , [0] => 10p , [1] => 20p )
ORDER BY KEY
ksort(): order by key (maintaining associations)
$a = array('z'=>'A', 'y'=>'C','k'=>'B','x'=>'B');
ksort( $a ); # Array ( [k] => B , [x] => B , [y] => C , [z] => A )
USER-DEFINED COMPARISON FUNCTION
usort(): compare using an user-defined function. (keys destroyed and renumbered starting from zero)
$a = array( '0'=>array('id'=>4,'n'=>'aaa') , '1'=>array('id'=>2,'n'=>'bbb')
usort($a, function ($a, $b) { #order by '[id]' contained in the elements #closure (php 5.3)
return ($a['id'] < $b['id']) ? -1 : 1; }); #Array ( Array ( [id] => 1 [n] => ccc ) ,Array ( [id] => 2 [n] => bbb ) ,Array ( [id] => 4 [n] => aaa ) )
uasort(): as usort but MAINTAINS the KEYS
HOW TO REMEMBER FUNCTION NAMES
sort = default sort behaviour: order by value and destroy keys
If the function name contains:
u = sort using [U]ser-defined function (Usort, Uasort, Uksort)
a = [A]ssociative: maintains key order (Asort, Arsort, uAsort)
k = order by [K]ey (Ksort, Krsort)
r = [R]everse order (aRsort, kRsort, Rsort)
OTHER ARRAY USEFUL FUNCTIONS
shuffle(): scramble array s contents. (keys destroyed and renumberted starting from 0)
array_rand($array, $number): return $number random elements from $array
array_multisort()
array_shift( array &$array ) ; return the array shifted by 1element off the beginning of array (remove the 1st)
array_slice( array $array , 3, 2, $preserve_keys); RETURNS 2 elements starting from the 4th. if $preserve_keys is true, the keys in the return array are the same in the original one
$a = array(0=>1, 1=>2, 2=>3, 4=>4, 3=>5, 5=>6);
$a = array_slice($a,3,2); #Array ( 4 ,5 )
array_splice(): remove the slice (REFERENCE) and return the removed part
$a = array(1, 2, 3, 4, 5, 6);
$returned = array_splice($a,3,2); #remove 2 elements from 4th elem. return the removed slice
# $returned = Array ( 4 ,5 )
# $a = Array ( 1 ,2 , 3 , 6 )
Thursday, December 10, 2009
Netbeans 6.8
New features:
- Symfony support (integrated prompt, syntax + help for command line code generator, shortucts) + YAML syntax support
- better code completion, supporting PHP 5.3 features (namespaces)
- PHPUnit improvements
- PHP application from remote servers
- SQL better auto completition
- Embedded Browser + Web Preview for HTML and CSS
Thursday, November 26, 2009
Checking PHP script performance with Xdebug
If the option is enabled, Xdebug will be able to trace and save information (time, details) about all the functions/methods called in the script (CLI or Apache).
The aim of the profiling is mainly recognizing bottlenecks or simply what parts of the code that are slow.
In order to analyze the log file created, use KCacheGrind or WinCacheGrind (see screenshots below).
Setup and docs at [http://www.xdebug.org/docs/
Configuration for Wamp (PHP 5.3)
#php.ini
[xdebug]
zend_extension=c:/wamp/bin/
xdebug.profiler_enable = 1
xdebug.profiler_output_dir=C:/
xdebug.remote_enable=on
xdebug.remote_handler=dbgp
xdebug.remote_host=localhost
xdebug.remote_port=9000
xdebug.remote_mode=req
Screenshots
Thursday, November 19, 2009
Profiling MySQL
There are lots of tools to profile, but I think it's very easy to make a customized code to save the data really needed.
The idea is save information about some queries in the production environment (about 1% of the queries is usually enough, depending on the traffic).
MySQL profiling
Hoping there is a class used to manage queries (or at least mysqli class), it doesn't take long to replace a function that manages the queries with something similar to the following code (written in a simple way to show the idea):
class DB extends mysqli {
...
function query ($q) {
$start = microtime(1);
$this->query($q);
$wtime = microtime(1) - $start;
#save 1% of the queries + info
if ( rand(0,100)<1>query("INSERT DELAYED INTO `ProfileData` (q,wtime,created,...) ($q,$wtime, NOW(), ...) ");
}
}
...
}
What other info to save ? some ideas:
- client IP
- other $_SERVER info: user-agent, request_method, etc...
- PHP backtrace (to understand which line launched the query)
- web server load
- mysql server load
- ...
example: queries grouping by query and showing the average time of the queries. In this way, you can find what queries are the slowest ones.
-- select the slowest queries (average time) in the last 24 h
-- exclusion of the queries executed only once to exclude missing sql cache
SELECT `q`,AVG(`wtime) as "medium time", COUNT(`id`) as "occurences"
FROM `ProfileData`
WHERE `created` > DATE_ADD(NOW(), INTERVAL -1 DAY)
GROUP BY `q`
HAVING COUNT(`id`) > 2
ORDER BY AVG(`wtime) DESC
Simple effective PHP debugging + backtracking
A valid solution might be a traditional "print_r"/"var_dump" + "exit"
Two problems:
1) accidental commits to the staging/production environment.
2) it takes time to understand where they are placed in the code, also because of the "exit".
Solutions:
Make a function to debug that
1) use a (external) constant (define) that define what is the environment and return without debugging and exiting if the environment is not the localhost one.
2) print the backtrace to easily find and remove the "breakpoints"
Code:
function pd($var, $useVarDump=false, $exit=true){
if (IS_PRODUCTION_ENV) return;
echo '<pre>';
if ($useVarDump) var_dump($var); else print_r($var);
echo "\n\nBACKTRACE:";
print_r(array_slice( debug_backtrace(false),1) ;
echo '</pre>';
if ($exit) exit;
}
MySQL dump importing
A working way to import a sql/dump file is to use the "mysql" executable
#localhost
mysql --u root -p --user=root --force [DBNAME] < [FILE.SQL]
Monday, November 16, 2009
PHP 5.3
My comments:
Performances
What I really consider good is the performance increasing (5/10%) that include a smarter behaviour with require/inclusion, smaller binary size and better stack performance.
Features
- Namespaces are OK, but not really necessary. A good code can be written also without them.
- I think the best feature is the late static binding. It was the only big lack about the PHP OO.
- Also closures are sometimes useful to write a clearer code. I've tested their performances (*) and it seems there are no decreasing using them, that's cool.
(*) array_map(function ($n){return($n * $n * $n);}, array(1, 2, 3, 4, 5)); #
- "goto": its utility (especially in a OO language!) doesn't make any sense to me. Very bad code readability with it.
- MySQLInd sounds very interesting to have better performances with MySQL. Client side query cache, written for PHP (not C/C++), performance statistics for bottle-neck analysis [read here]... wow ! I'll probably test it soon although (according to some blog posts) the performance increasing seems not very high.
- Hundreds of bug fixing and improvements, including Directory iterator and date functions => well done PHP community !
