Thursday, May 13, 2010
Saturday, April 24, 2010
Thursday, April 22, 2010
Site moved
Ufortunately it's not been possible to move the "google followers" to the new site (google limitation), so I've had to make another widget. If you keep following this blog, please join the new site (box on the right).
Also the feed is changed to http://feeds.feedburner.com/phpntips
The new address is:
http://www.phpntips.com/
Thanks !
Tuesday, April 20, 2010
Custom rules for zend standard rewrite router
Routing is basically how zend associate URLs tothe controllers, actions and parameters of the application (similar to apache mod_rewrite but PHP based therefore much more powerful).
Default routing
As it is known, the default Zend routing uses the following schema:
[controller]/[action]/[var1name]/[var1value]/ [var2name]/[var3value]/ ... /[varNname]/[varNvalue]
If the controller or action are not specified, the ones with name “index” are used for routing.
How to set rules
First of all, all the rules have to be attached to the router, that can be returned by using getRouter() on the frontController object (obtainable with singleton: Zend_Controller_Front::getInstance()).
The router is an object of type Zend_Controller_Router_Rewrite, and contains the method addRoute($name, Zend_Controller_Router_Route_Interface $route)
So, we need to attach object of classes that implements Zend_Controller_Router_Route_Interface.
Static routing [zend manual]
The simplest is used for static for rules without variables inside:
$route = new Zend_Controller_Router_Route_Static('login', array('controller' => 'auth', 'action' => 'login') );
After this rule is attached, the URL /login will be the same as /auth/login
Standard routing (with optional default and requirements on parameters) [official doc]
$route = new Zend_Controller_Router_Route('archivenews/:year',
array('controller' => 'news', 'action' => 'archive', 'year' => ‘2010’ /*default value*/ ),
array('year'=>'\w{4}') /*requirement on parameter*/
);
- The string 'archivenews/:year' is the route. The placeholders starting with semicolon (just “:year” in this example) are variables ( that will replaced with the real values in the URL).
- The URL /archivenews/2008 will call the controller news, action archive, and will set the parameter ‘year’ to 2008 (obtainable with $this->_getParam('year') inside the controller).
- The URL /archivenews will call the same controller and action, with ‘year’ to 2010 (default).
- Validation: The URL /archivenews/20008 will not match any rule, as the validation fails. If the validation (third argument) is removed, the same URL will call the same controller and action with year set to ‘20008’
- Default value: If the default value is not set (item ‘year’ not present in the second argument), the rule /archivenews will not match
RegEx routing [main]
It supports regular expression inside the route instead of passing as a third argument (slightly faster than the previous one).
$route = new Zend_Controller_Router_Route_Regex('archive-news/(\d{4})',
array('controller' => 'news', 'action' => 'archive')
);
With this rule we’ve defined the same rule as before, with no default values.
As you probably have noticed, the rule does not contain the name of the variable (:year). To get it, use $this->_getParam(1) as “1” is the ordinal number of the placeholder (regular expression) in the route.
Attaching rules to the router
As already said, the rules has to be attached to the router
$ctrl = Zend_Controller_Front::getInstance();
$router = $ctrl->getRouter();
// use $route set above
$router->addRoute('routeName', $route); /*note: do not use the same route name for different rules or they will be overwritten and ignored*/
Post moved here:
Custom rules zend standard rewrite router
Inside wordpress: notes about common variables and functions to add extra features
What we can do with wordpress: fixed pages, site news (that are blog posts), simple search, multi-level page and news content management, WYSIWYG editor, changeable themes, lots of free themes already available, url rewriting etc...).
Sometimes we need to extra customize the frontend aspect of the site/blog, and we have to modify the standard behaviour of wordpress. It needs to know a little how its atchitecture, how it works and some of its functions.Obsolete architecture
Since the first wordpress was released on 2003, its architecture is still using a non OOP style and it has nothing to do with a modern framework, nor a MVC application. Lots of informations are kept in global variables and there are thousand of functions.
Loading chain and main global variables
Wordpress (v.2.9.2, the latest at the time of writing) loads the content in the following order/hierachy:- index.php includes wp-blog-header.php that
- includes wp-load.php
- defines ABSPATH (root directory)
- sets error_reporting
- includes wp-config.php
- defines db parameters, lang, prefix
- includes wp-settings.php
- unregister globals, fix ISS, check PHP versions and mysql extension
- defines WP_CONTENT_DIR, WPINC ,WP_LANG_DIR
- requires compat.php (defines function not existing in some PHP versions), functions.php, classes.php
- includes wp-includes/wp-db.php that istantiates the global variable $wpdb (object of the class wpdb) with methods: get_row, insert, prepare, query,insert, update, etc...
- includes wp-includes/cache.php that defines the functions wp_cache_add, wp_cache_get, wp_cache_init (initially called), etc...
- includes all the other files in wp-includes
- instantiates some global variables (often used)
$wp_the_query = $wp_query = & new WP_Query();
$wp_rewrite = new WP_Rewrite();
$wp = new WP(); #defined in wp-include/classes.php
$wp_widget_factory = new WP_Widget_Factory();
$wp_locale = new WP_Locale(); - init wordpress
$wp->init();
- unregister globals, fix ISS, check PHP versions and mysql extension
- defines db parameters, lang, prefix
- launch wp() that launches $wp->main() (class WP)
the method main() calls the other (quite self-explanatory) methods: parse_request (parsing of the URL and ), send_headers, query_posts (), handle_404 (), register_globals () - includes wp-includes/template-loader.php, that depending on the content and user agent, includes the templates for homepage, or single page, or category etc...
Functions used to switch the content and include the template:
if ( is_home() ) { include( get_home_template() ); }
if (is_page() ){ include( get_page_template() ); }
[... the same with 404, search, single, category, date,archive,paged..]
if ( is_feed() ) {
do_feed(); }
- includes wp-load.php
In case the homepage is loaded (and the default template is enabled), the theme templates are loaded. For the homepage and default template, the file included is
/wp-content/themes/default/
These functions call the homonym methods of the global object $wp_query of class WP_Query (wp-includes/query.php). This object contains most of the variables needed for displaying the blog (posts, counting of posts and comments, type of page :single/archive/list/search/home/ query string, request, etc...
Some functions used inside the main template:
have_posts() #returns true if there still are posts to display in the current page
the_post() #get next post (iterator)
the_ID() #prints the ID of the post
the_content() #prints the content of the post
Other common and useful functions:
get_option($name) gets the options (using cache) from the DB table wp_options.
is_paged(), is_search(), is_category() and others: they return the correspondent boolean values in the $wp_query global object if the current page is respectively paged, a search page, a category page etc.. See other function (and methods) in the file wp-includes/query.php
To make queries:
use the object $wpdb (wpdb class), and execute the method query() on it. This variable is visible inside templates (as well as $posts, $post,$wp,$user_ID etc...)
$wpdb->query("delete from ...");
Post moved here: Inside wordpress variables functions extra features
Thursday, April 15, 2010
sessions vs cookies with load balancer
When dealing with sessions with PHP, we have two main solutions:
- set manual cookies
One approach is using directly the PHP functions to set the cookies. When possible I don't use manual cookies(except than keeping an hash string for the user identity or keep the session after the browser is closed) as there are lots of issues (datas kept in the user browser so they have to be validated at each request, difficulty to store complex datas, browser compatibility or partial cookie blocking etc...).
- session functions
A much easier approach is using the session functions. The session is automatically managed by PHP and the superglobal array $_SESSION is available with persistent user datas, thanks to the session cookie automatically managed.
Advantages: data stored in the server, easy to save arrays and custom objects, superglobal array immediately available and semplicity in writing the code.
Disadvantages: not possible to keep it after the browser closes (except a custom save handler on disk or db) , not possible to specify URL path and domain for the session.
- server balancer issues -> cookies !
Today we had some issue with our server load balancer. We realize that it didn't support sticky sessions, so at every redirect (also to the same page because of some rules) the session datas (kept through session functions) were deleted. In order to meet a deadline, we set a manual cookie to keep the data needed.
Sunday, February 28, 2010
Singleton is bad !!
At the beginning it made me a little astonished as it's one of the most widely used design patterns, in addition ZF and lots of other projects use it. However, after a while I agreed the idea. Singleton actually had created some problems when I had to do some class testing and refactoring in some PHP code.
Why is it not a good practice ? Singleton is appropriate when dealing with threads (JAVA, C#), but as a matter of fact in PHP applications it's used just as a global constant and it creates dependency injection. That's a bad practice as it couples the components/classes and usually makes difficult unit testing, refactoring and structural changes.
class A {
public function f(){
$c1 = c1::GetInstance(); #bad !!
# use $c1
$c2 = c2::GetInstance(); #bad !!
# use $c2
}
}
What's the alternative ? Simply, instead of retrieving the instance in the method of the class, retrieve it from an internal class field after it has been set by the constructor.
class A {
private $c1;
private $c2;
public function __constructor(C1 $c1, C2 $c2){# alternative, use Interface name
$this->c1 = $c1;
$this->c2 = $c2;
}
public function f(){
# use $this->c1;
# use $this->c2;
}
}
What about static methods ? In a static context, $this is not available.
One first solution occurs in my mind it's passing the instances to all the the static methods. But if there are lots of methods and external dependencies, another solution might be using another static method to get all the instances needed, in order to move all the external dependencies to one method and make easier managing the class. A kind of internal 'Registry' design pattern.
class A {
const INST_c2 = 1;
const INST_C2 = 2;
public static function getInstance($instance){
if ($instance==self::INST_C1){
return c1::GetInstance();
} else if ($instance==self::INST_C2){
return c2::GetInstance();
}
}
public static function f(){
$c1 = self::GetInstance(self::INST_DB);
# use $c1;
$c2 = self::GetInstance(self::INST_C2);
# use $c2;
}
}
Of course there are other solutions, more or less convient depending on the needs.
Any other ideas ?
PHP UK conference 2010 talks
I choose the excellent PHP-strictly-related talks of S.Priebsch, F.Potencier and J.Schlüter as well as the good Seguy's talk about security (and the quite unsatisfying Hudson's talk).
Some interesting comments on joindin.
slides
The lost art of simplicity - Josh Holmes
slides + transcript
RDBMS in the social networks age - Lorenzo Alberton
slides
AntiPHPatterns - Stefan Priebsch
slides
Would you like docs with that? - Stefan Koopmanschap
slides
Database optimisation - Remo Biagioni
not found :(
PHP 5.3 in practice (dependency injection and lambda/closures)- Fabien Potencier
slides
Living with legacy code - Rowan Merewood
slides
PHPillow & CouchDB & PHP - Kore Nordmann
slides
'In search of...' - integrating site search systems - Ian Barber
not found :(
Regex-fu - Juliette Folmer
notes
Best practices in web service design - Lorna Mitchell
slides
Other talks:
Hidden features - from core to PECL - Johannes Schlüter
Cloud computing for PHP using the Windows Azure SDK - Rob Allen
Web and mobile application monetisation models - Chuck Hudson
PHP code audits - Damien Seguy
PHP on the D-BUS - Derick Rethans
Saturday, February 27, 2010
PHP UK 2009 conference - talk slides
For some of them, a few-line-summary.
The future's so bright, I gotta wear shades (keynote) by Aral Balkan
not found :(
Clouds on the horizon? Get ready for Drizzle by David Axmark
slides
Drizzle, a light faster version of mysql: only UTF8, features as plugin, semplified protocol. BSD licence.
Flex and AIR for PHP programmers by Mihai Corlan
page
Flex is an open source framework to build flash application for developers, without using Authoring tools. It includes teh SDK, an IDE and compilers as well as a rich library.
Basically, the frameworks allows to to write flash applications using HTML+CSS language + embedded OOP scripts, much easier then action script.
Living with Frameworks by Stuart Herbert
slides
Myphp-busters: symfony framework by Stefan Koopmanschap
slides
Of Lambda Functions, Closures and Traits by Sebastian Bergmann
slides
PHP on Windows - the undiscovered country by Hank Janssen
video
Security-Centered Design - exploring the impact of human behavior by Chris Shiflett
slides
Sharding Architectures by David Soria Parra
slides
Master / slave combination pros and cons, table spliting, mysql proxy with LUA
State Machines to State Of The Art: Smart, efficient design using ReST & MVC by Rowan Merewood
slides
What's new in PHP 5.3 by Scott MacVicar
slides
Sunday, February 14, 2010
Upload a tree of files and subdirectory to a remote FTP server
Problem: I've got an extremely poor upload bandwith in my house in UK. So, I've used another hosting with SSH (dreamhost, in US) and:
1) got data from the 1st hosting (step1). Uploaded a php files that runs "tar -cf all.tar *"m, executed a "wget" to get the tarball, extracted the tarball.
2) uploaded to the second Italian windows hosting (step2).
ncftpput -R -v -u "username" ftp.site2.it /fpt-root-folder .
Weird tricky situation, isn't it ?
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.