Thursday, March 26, 2009

PHP PDO bug

Today i just tried to do a simple query 'SELECT * FROM content LIMIT 0, 15'. Since i have been extremely on PDO, i wrote the query in this way, 'SELECT * FROM content LIMIT :offset, :limit', $bind = array('offset'=>0, 'limit'=>15). I got this error:

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''0', '15'' at line 1

And then i found this is a PHP bug: http://bugs.php.net/bug.php?id=40740&edit=2

Bug #40740 PDO::execute() errors when parameters are used in LIMIT clause

That is ok. For someone like me who uses PHP to an extreme extent, getting some PHP bugs is normal. I've seen another PDO bug before, which had been fixed. That bug only exists in one PHP release.

What really surprises me is submitted at 6 Mar 2007, while at the end of this bug report, i found this 'Still not fixed in the 5.2.8 release'. I am using 5.2.8!

Friday, March 20, 2009

JQuery & Html Entities

htmlentities() is well known for PHP developers. JQuery can do the same thing at client side. Here is the interesting blog : http://debuggable.com/posts/encode-html-entities-with-jquery:480f4dd6-13cc-4ce9-8071-4710cbdd56cb

Actually, it is quite simple: $('#content').text('This is fun & stuff').html(); // evaluates to "This is fun & a m p ; stuff"

However, i have another issue. I send a json data { myValue: 'AT& a m p ;T' } to jquery. And what jquery is supposed to do is $("#myInput").val(myValue). This, however, will display AT & a m p ;T in the input field, instead of AT&T, the one i really want to show.

Instead of writting your own html entities parser, here is a hacky solution:
var realValue =$("#js_temp").html(myValue).text();
$("#myInput").val(realValue);

Tuesday, March 17, 2009

JQuery event functions do not work for dynamic added elements

$("a").click(function () {
alert("I was clicked");
});

<a href="http://www.blogger.com/post-edit.do">click me</a>

If you click the link, a window will popup. However, if you use JQuery dynamicly add some new <a> elements, they won't work with the click function. For example,

$("p").append("<a href='#'>I am added dynamically</a>"), and if you click the link, you will find that the function doesn't work at all.

Monday, March 16, 2009

Zend framework source code learning - Zend_Loader

include 'Zend/Loader.php';
Zend_Loader::registerAutoload();

The above two lines can save us from those long reqire_once list on top of php files. Let's have a look at the registerAutoload().

The method definition is public static function registerAutoload($class = 'Zend_Loader', $enabled = true). If we don't pass any parameters, the default class is Zend_Loader, and $enable is true, which allows the function to call spl_autoload_register.

if (!function_exists('spl_autoload_register')) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('spl_autoload does not exist in this PHP installation');
}
It checks if spl_autoload_register function exists, because the magic autoload relies on this function.

self::loadClass($class);
loadClass() is the sole method of Zend_Loader. It looks through the path and directory, based on the $class name, and tries to load the class file. For example, if the $class is 'Zend_Log_Writer_Stream', it looks through 'Zend/Log/Writer/' and tries to load Stream.php file.

$methods = get_class_methods($class);
if (!in_array('autoload', (array) $methods)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception("The class \"$class\" does not have an autoload() method");
}
spl_autoload_register(array($class, 'autoload'));
The codes check if the class possesses autoload method and tries to register the method.

Zend_Load defines and autoload method, which actually calls the loadClass().

So that is how Zend_Load works. If we call a class not defined, it automatically searchs the class file by its class name in include_path, and load the class file if it is found.

I havn't done the test by myself. But some articles on internet point out that Zend_Loader::registerAutoload() is bad in performance. It is quite possible, based on its code. So the developer must find a balance between speed and convenience.

Zend framework source code learning - Zend_Registry

Zend_Registry extends ArrayObject, which is a class in Standard PHP Library(SPL).
Let's take a look at its set method:
public static function set($index, $value)
{
$instance = self::getInstance();
$instance->offsetSet($index, $value);
}
We can see, although it is a static method, it implements a singleton inside: $instance = self::getInstance().

offsetSet($index, $value) is a method of ArrayObject. It will set the value at the specified $index as $value.

Now let's check through get method:
public static function get($index)
{
$instance = self::getInstance();

if (!$instance->offsetExists($index)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception("No entry is registered for key '$index'");
}

return $instance->offsetGet($index);
}
It gets a singleton instance and tries to call offsetGet($index), which is another ArrayObject method to return the value at $index. If the specified $index doesn't exist, it throws an exception.

We use Zend_Registry to store the resources that must be accessed through the whole web site, such as database resource.

Sunday, March 15, 2009

Zend framework source code learning - Zend_Config

Zend_Config class

To understand this class, we only need to look through its 3 methods.
The first is, naturally, its constructor.

public function __construct(array $array, $allowModifications = false)
{
$this->_allowModifications = (boolean) $allowModifications;
$this->_loadedSection = null;
$this->_index = 0;
$this->_data = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$this->_data[$key] = new self($value, $this->_allowModifications);
} else {
$this->_data[$key] = $value;
}
}
$this->_count = count($this->_data);
}
Many developers prefer using arrays in php file to save config data, such as $option['path'] = ''. From this constructor, we know that to load the config data, we can instantiate a Zend_Config class in this way: $config = new Zend_Config(require 'config.php');

Zend_Config use getter to retrieve config data. It provide magic method __get as well. However, __get also call the getter.

public function get($name, $default = null)
{
$result = $default;
if (array_key_exists($name, $this->_data)) {
$result = $this->_data[$name];
}
return $result;
}

public function __get($name)
{
return $this->get($name);
}

So, to get the value of $option['path'], we can use either $config->get('path') or $config->path. I think most of PHP developers(including myself) cannot resist the temptation of using the latter one to get data.

That is pretty enough for Zend_Config class.

Thursday, March 12, 2009

Test javascript in IE

Firefox is a perfect companion to web developers due to its web development tools like firebug. However, in some cases it might be too good especially when we are working on javascript. Or, maybe more precisely, i should say IE sucks! However, we have to accept such a reality that most internet users still use IE as their default and only browser. So, just keep in mind that you should test your javascript in IE ALWAYS. Don't assume that JQuery or other javascript frameworks or libraries can take care of this issue for you. The truth is, none of them can. In the world of javascript, we don't have the magic like java and java VM that let you write once, run everywhere.

Tuesday, March 10, 2009

Another article about PHP DAO

Decoupling models from the database: Data Access Object pattern in PHP

http://codeutopia.net/blog/2009/01/05/decoupling-models-from-the-database-data-access-object-pattern-in-php/

Monday, March 9, 2009

Zend_Db component

Zend framework provides some database access components. A common feature of these components is, it can access/query database in OO way. So, it is quite possible that you won't see a whole, integrated sql query in code. Instead, you probably will see a lot of these queries: $where = 'where id = ?'; $db->select('*', $where);

When regarding database query, i am not a supporter of OO. I prefer writing full,whole, or integrated sql, even some times this means duplication. For example, i probably need to use two queries: 1. SELECT * FROM user WHERE id=?; 2.SELECT * FROM user WHERE username = ?. I would like to write them twice, instead of write them in this way: $select = "SELECT * FROM user"; $whereId = " WHERE id=?"; $whereName = " WHERE username=?". Finally, I would just run the whole query by $db->query($sql);

So my model will not extend from any Zend_Db components. And there is no data access object carried with model. I have DAO layer. Instead of calling $user->save(), i would call $daoUser->save($user). And in my dao object, it is always like this: $sql = "SELECT * FROM user"; $db->query($sql);

Zend_Form

I give Zend_Form a couple of tries. I recognize it is a really cool component. However, i think it kind of violate the layer separation law. What if a designer wants to decorate the form? He must open up the PHP file and learn how Zend_Form work?

In spite of this, I cannot resist the temptation of using this component. The benefit is it can save a lot of time. With Zend_validator and Zend_Filter, Zend_Form can finish most of form processing job for you. You, as a developer, probably just need to add some extra own validators and that is it!

Performance, easy development, code solid

Performance is an issue often mentioned by developers. Regarding zend framework, one consideration is using Zend autoload or not. Autoload can make our life much easier. As long as we specify the file name and class name in accordance with name space rule, we don't need to put include/require on top of files. Some articles on internet, however, point out that zend autoload slow down the web site's performance. They prefer puting lot of include/require statement on top of files.

For me, i prefer using autoload, because not only it really saves a lot of time, and makes the code look more clean, but also most problems of a web application, based on my opinions, are caused by coding errors, bugs instead of performance.

some thoughts of using zend framework

1. Where is business logic located? Controller + Model? Fat controller + Thin model or Thin controller + fat model, or controller + model + another business logic layer?

2. If the web application is organized in modules, and we don't want to use zend autoload due to performance consideration, how to access one module's data/model from another module?

3. Active Record or DAO? I personally prefer DAO. And the reason is obvious: data access get separated from business model, and your model won't become heavy. Just think of a situation: send email to millions of subscribers, if each subscriber has to carry db accesss object, that is gonna take a lot of resurces.
Here is an article about active record and DAO: http://blog.astrumfutura.com/archives/128-DAO-vs-ActiveRecord-DAO-Wins.html

Thursday, March 5, 2009

Integrate Smarty with Zend_Layout

If you can endure adding {include file="header.tpl"} and {include file="footer.tpl"} in all of your template files, then you don't have to worry about this issue. And you are lucky! (You are even more lucky if you don't use smarty at all!)

Unfortunately, I cannot accept this kind of coding, so I have to face the pain and find out how to integrate smarty with zend_layout.

I can only find one article from internet regarding this issue. The article is here: http://anders.tyckr.com/2008/03/12/implementing-zend-layout-and-smarty-using-zend-framework-mvc/

It gives us a detailed solution to implement smary with zend layout, and it DOES WORK! Thank God...

CLI/Console program with Zend Framework

You can google this tutorial "PHP frameworks, Part 5: Integrating external tasks" for dealing with working outside the frameworks.

Even for a web application, we may need to run scripts in command line in some cases. For example, a cron job. And we want to use our models and Zend framework components. The most important thing is to setup include path to include your Zend library and your models. For example, if Zend is placed in 'library' folder, we can
set_include_path('.' . PATH_SEPARATOR . ROOT_DIR . '/library/'
. PATH_SEPARATOR . ROOT_DIR . '/application/models/'
. PATH_SEPARATOR . get_include_path());

require_once('Zend/Loader.php');
Zend_Loader::registerAutoload();

That is it. Now you can use your models and Zend components as you use them in your web application. For example,

$config = new Zend_Config_Ini(ROOT_DIR . '/config/config.ini', 'cli');
Zend_Registry::set('config', $config);
//set up default time zone
date_default_timezone_set($config->date_default_timezone);

// configure database and store to the registery
$db = Zend_Db::factory($config->database);
Zend_Db_Table_Abstract::setDefaultAdapter($db);
Zend_Registry::set('db', $db);

//do sth
$user = new User();
$user->save();

$logFile = Zend_Registry::get('config')->logFile;
$log = new Zend_Log(new Zend_Log_Writer_Stream($logFile));
$log->info('a new user is saved');

Zend_Log limitation

I researched Zend_Log for a while today. My case is I want to user one logger and log messages to different files based on the message type. The message type is not Zend_Log's message priority. It is more event/action based. For example, i want to log login information to login.log and pay information to pay.log.

Although we can add multiple writters to a logger, we can't specify which writter we want to use. Well, i should say, I didn't find out how to specify a writter for Zend_Log.

Sure i know where there is an issue, there is a solution. But I wish next Zend framework release could bring us a better Zend_Log

smarty $compile_id for different $template_dirs

We might have different template dirs storing template files with an identified name. For example, we could have /Auth/index.tpl, /Buy/index.tpl. However, Smarty uses only one compile dir, and Smarty is not that smart. To display the two index.tpl correctly, we must specify $compile_id. If you set a distinct $compile_id for each template_dir, then Smarty can tell the compiled templates apart by their $compile_id.

Wednesday, March 4, 2009

2011年全球手机成人内容市场价值33亿美元

2011年全球手机成人内容市场价值33亿美元

发表日期:2006年11月29日 出处:CNET New
-----------------------------------------------------------------------------------------------

  就如同当年的互联网媒体产业,如今的移动内容市场也走上了迅速繁荣的老路:色情内容服务。

  据CNET News.com报道,据市场调查机构Juniper分析家预测,到2011年的时候,全球移动成人内容服务市场总价值将达到33亿美元,实际上,该数字在今年已经达到了14亿美元。

  据悉,欧洲是最大的移动色情内容服务市场,在色情内容的提供和需求方面,均走在全球的第一位。与此同时,亚太地区则在色情服务产业内排名第二。

  据Jupiter分析家透露,移动成人内容服务的崛起,与手机技术的迅速发展不无关系,可以说是技术的飞跃带动了一次又一次服务的创新。据统计,目前绝大多数手机色情服务还属于文字形式,而随着未来3G手机网络的逐渐普及,更多的多媒体形式服务将登陆移动市场,例如图片、音频和视频等,届时更为丰富的色情内容将出现在世面,而色情服务基础,也将从呆板的文字过渡向更为刺激的图像世界。据一份手机产业报告,到2011年的时候,移动市场70%的营收将来自于媒体服务,而不再是简单的硬件销售。

  “手机色情服务是一块巨大的市场,实际上,成人内容服务总是可以拉拢某一媒体平台的迅速发展。”Jupiter分析家表示。据悉,目前的手机成人内容服务还处于起步阶段,大多数用户发送含有成人内容的文字信息,只是为了取悦自己的伴侣而已。

Mobile content revenues to grow exponentially to 2009

From: http://www.wiliam.com.au/wiliam-blog/mobile-phone-and-mobile-content-to-grow-exponentially-to-2009

According to an article (Mobile revenue to top $1bn by 2009, AAP) in The Sydney Morning Herald, revenues from mobile content (mobile phones) in Australia are set to explode, exceeding a fantastic $1 billion on 2009.

Revenues from Australian mobile content were $129 million in 2004, with personalisation services such as mobile phone wallpapers and ring tones accounting for 69%.

Based on study by Frost & Sullivan, the key areas of mobile content growth will be entertainment, enterprise applications and productivity services; adult services are considered entertainment in the study, and are predicted to be one of the biggest movers (122% growth).

Also mentioned is the growth of high-bandwidth applications and mobile content (3G (and 4G?) such as mobile video, predicted to account for 13% of US revenues by 2009.

There are a variety of obvious factors behind the growth including bandwidth (3G) and increasing demand from ever-savvier consumers.

The article concludes by predicted the challenge for the industry being establishing sustainable and successful business models; 1999, here we come again!

At Wiliam, we have followed the emergence and growth of the mobile content industry, and have developed a number of mobile applications with Vodafone Australia in the past year; only a few weeks back, we completed a project with client Mogenic, where we integrated our Content Management System sitedock with the Vodafone MMS gateway to allow participants to submit their MMS photos (mobile phone photos) directly to the Mogenic website.

In fact, several of our current websites in production are being built in xHTML, allowing for easier portability of content to mobile phones.

I suspect that within six months, all of our content will be mobile-ready, and that within twelve months, clients will place emphasis on mobile optimisation of their content.

Start coding on project officially

I officially start coding on my new project now. Since i decided to use Zend Framework, which is pretty new to me, in the first several days i just try to set up the framework and the file structure. I also implement Authentication and ACL, integrated Smarty with Zend.

I personally don't like smarty. But many other php developers like it, so at this point i compromise a little bit.