Archive for the ‘PHP’ category

problem with multi fastcgi_finish_request requests in nginx

May 1st, 2013

The php server nginx has a very handy function fastcgi_finish_request(). If fastcgi_finish_request is called in a function, the function will return immidiately but still do the job in background. So it is intuitive to think of using fastcgi_finish_request() to do some jobs in parallel when needed.

However, when a process call the fastcgi_finish_request() many times in a row, the later calls have to wait for the previous call to finish. So it’s not such a big help when you call fastcgi_finish_request() many times in a row, because all these requests will be executed in sequence. Rather you should put all the long calls in a fastcgi_finish_request() call.

For example:

function a() {
     long_work(); // 1st call
     // if we write a log here, we'll find 1st call immediately returns.
     long_work(); // 2nd call
     // if we write a log here, we'll find this 2nd call will have to wait for 10s before it returns.
}

function long_work() {
    sleep(5);
    fastcgi_finish_request();
}

A workaround to mimic multithread with fastcgi_finish_request() is to use curl. We put the long work in a php file, and then use curl to request the php file.

// ------ long_work.php ----------
long_work();
function long_work() {
    sleep(5);
    fastcgi_finish_request();
}


And then in function a(), we can request long_work many times.

function a() {
    // curl( 'http://localhost/long_work.php' ); // 1st call
    // curl( 'http://localhost/long_work.php' ); // 2nd call
}

PHP Hash Chinese Character or String

April 22nd, 2013

Hash a Chinese character or string into a integer number. This might be useful when one wants to split a huge table which is indexed by Chinese strings horizontally into many tables.

	/**
	 * Hash a chinese charactor into an int number.
	 * @param string $c A chinese character
	 * @return number
	 */
	public static function hashZhChar($c) {
		return (ord(substr($c, 0 , 1)) -176)*94 + ord(substr($c, 1, 1)) - 161;
	}
	/**
	 * Hash a chinese string into an integer number.
	 *
	 * @param string $s A chinese string.
	 * @return number
	 */
	static function hashZh($s) {
		$first = mb_substr($s, 0, 1, 'UTF-8');
		$last = mb_substr($s, -1, 1, 'UTF-8');
		$middle = mb_substr($s, intval(mb_strlen($s, 'UTF-8')/2), 1, 'UTF-8');
		return self::hashZhChar($first) + self::hashZhChar($last) + self::hashZhChar($middle);
	}
	

Thinkphp memory leak? ThinkPHP内存泄露?

April 8th, 2013

Recently I encountered a problem with writing scripts with ThinkPHP framework. My scripts usually take long time to finish and have lots of communication with Mysql. However I find with ThinkPHP it’s very easy to come across with problem of out of memory, even if I’ve set the memory limit for each script to 256MB, which is quiet high!

Today I finally decided to carefully check this problem. The first thing came into my mind was that this must have something to do with db operations since I’m have heavy mysql operations. So I write a small piece of code to test whether I was right. Here is the code:

public function test() {
$mdl = M('t3');
$i = 0;
while(++$i < 300) {
$mdl->where('id=1')->select();
if($i % 50 == 0) {
echo number_format(memory_get_usage()) . "
\n";
}
}
}

I run this code and found this memory usage kept increasing which indicates there really exists a memory leak. Here is a sample output:

4,125,264 
4,146,688 
4,169,136 
4,189,536 
4,211,984

And then I replaced select() with buildSql() which only builds the sql instead of querying the db, I found that the memory stopped increasing. So the problem locates in the db operations!

After diving a bit in the source code, I found that the cause is the function Db::debug() which utilizes function trace(). Here is the Db::debug() definition:

    protected function debug() {
        $this->modelSql[$this->model]   =  $this->queryStr;
        $this->model  =   '_think_';
        if (C('DB_SQL_LOG')) {
            G('queryEndTime');
            trace($this->queryStr.' [ RunTime:'.G('queryStartTime','queryEndTime',6).'s ]','','SQL');
        }
    }

I realized that at the moment my application is still in the debug mode, which by default set the DB_SQL_LOG true. So now the solution is obvious: simply switch off the sql log, either by defining it in the config file such as Conf/debug.php or set it dynamically like this C(‘DB_SQL_LOG’, false). Because my website is still under development thus I need it on. So I choose the latter to set it dynamically in my script file.

But how the memory leak happens still remains uncovered. I’ll check it later.

How to install MemCache on Windows 7 X64 for PHP with WAMP

August 22nd, 2011

Basics

The memcache sonsists of 2 parts: the server MemCached and the client MemCache.

  • MemCached is the cache server, the same as Mysqld (mysql server), which save and feed cache to clients.
  • MemCache is a client. With php, we need to install it as a mod, just the same as pdo_mysql (php_pdo_mysql.dll on windows).

Install MemCached

  • Download memcached from http://code.jellycan.com/memcached/ (get the win32 binary version). Here we suppose you extract the memcached in d:\memcached\.
  • If you are on Sindows Vista/7, rightclick on memcached.exe and select Properties; click on the Compatibility tab. At the bottom you’ll see Privilege Level, check “Run this program as an administrator”.
  • Open the command line by Win + R (or Start -> All Programs -> Accessories -> Command Prompt), and then run: d:\memcached\memcached.exe -d install to install the service.
  • Still in the command line, run d:\memcached\memcached.exe -d start, or net start "memcached Server" to start the service.
  • Check whether the service is running. Open Windows Task Manager, go to Services tab, you should find status of “memcached server” is “Running”.

Install MemCache php module

Note

  • To change MemCached memory size (default is 64mb), go to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\memcached Server in your registry, find the ImagePath entry and change it to:
    “C:\memcached\memcached.exe” -d runservice -m 512
  • More details see: memcached -help

SQLSTATE[HY000]: General error: 2053 in ZF

May 15th, 2011

After updating the PDO, my program began to see some weird problems. One of them is “SQLSTATE[HY000]: General error: 2053″. After some time,  I finally found that it is because I passed NULL to the second parameter ($bind) of Zend_Db_Adapter_Abstract::fetchAll($sql, $bind = array(), $fetchMode = null).

So, instead of this:

$popList = $this->getAdapter()->fetchAll($sql, null, Zend_Db::FETCH_OBJ);

one should:

$popList = $this->getAdapter()->fetchAll($sql, array(), Zend_Db::FETCH_OBJ);

when you don’t need to bind any parameter with the SQL.

show / download image with PHP

March 9th, 2010

To show a image in browser:

$file_path = ICON_DIR . $_GET['f'];
// TODO check file_path security
$file_name = basename($_GET['f']);
$fileLineArray = file($file_path);
header(‘Content-Type: image/jpeg’);
header(“Content-Disposition:filename=$file_name”);
foreach($fileLineArray as $fileLine)
echo $fileLine;

To force the browser to show the download dialogue, add a attachment header:

header(“Content-Disposition:filename=$file_name”);
header(“Content-disposition: attachment; filename=$file_name”);

php session operations

February 26th, 2010

* get session id: session_id(), but remember to session_start() before getting the id.

* session_decode($data), this will decode the data and store them into $_SESSION.

reference: http://www.php.net/manual/en/ref.session.php

Zend Framework (>=1.8) Step By Step

January 18th, 2010

Index:

  • environment set-up: eclipse / pdt / xDebug
  • quick start: zend.com / akrabat.com
  • zend application
  • db
  • auth / acl
  • router
  • session
  • module
  • ajax
  • cache
  • captcha / file
  • mail
  • test
  • performance
  • server clusters

Books and references:

Zend_Session_SaveHandler_DbTable doen’t work

January 15th, 2010

My current ZF version is 1.9.4. However, because my application started from 1.7.x, I wrote all bootstrap code in index.php. So we config Zend_Session_SaveHandler_DbTable like this as the document said in index.php:

$config = array(
‘name’                 => ‘session’,
‘primary’              => ‘id’,
‘modifiedColumn’  => ‘modified’,
‘dataColumn’        => ‘data’,
‘lifetimeColumn’    => ‘lifetime’
);
$saveHandler = new Zend_Session_SaveHandler_DbTable($config);
Zend_Session::setSaveHandler($saveHandler);
Zend_Session::start();

And in indexAction of IndexController, I tried to test it like this:

$session = new Zend_Session_Namespace();
$session->name = “newsbag”;

But nothing happened. There was no data inserted into the session table.

But later, I create a totally new blank project following the Quick Start of ZF & Tutorial: Getting Started with Zend Framework 1.9, it worked!

Still trying to figure out what the problem…

========== update 1 ============

Now the problem seems to be caused by the Zend_Controller_Front instance in index.php. Because when I tried to add self-defined routers in index.php in the blank project mentioned above like this:

// ROUTER
require_once ‘Zend/Controller/Router/Route.php’;
$config = new Zend_Config_Ini (‘../configs.application.ini’, ‘routers’);
$router = new Zend_Controller_Router_Rewrite();
$router->addConfig($config->routes);
$frontController->getRouter()->addRoutes($router->getRoutes());

the Zend_Session_SaveHandler_DbTable refused to work.

So DON”T instance Zend_Controller_Front in index.php.

BTW, the possible way to set routers in ZF (>= 1.8.0) would be in Bootstrap.php:

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
function _initRouter(array $options = null) {
$frontController = $this->getResource(‘FrontController’);
$config = new Zend_Config_Ini (‘../application/configs/application.ini’, ‘routers’);
$router = new Zend_Controller_Router_Rewrite();
$router->addConfig($config->routes);
$frontController->getRouter()->addRoutes($router->getRoutes());
}
}