php multi-thread

今天突然想看看PHP多线程的问题,发现很多人讲PHP的多线程其实是多进程,唉,破灭了!!!网上给PHP的模拟多线程提出了几种方案,下面仅摘录:

There are a few solutions, varying from “Hmmm, just about OK” through to “Poke out your eyes”.

1. Write your multithreaded code as a PHP extension. Probably the most supported, but you need to write in C (or another language supported for extensions).
2. Spawn child processes onto the underlying OS, and read/write to their input/output with standard file handles. See popen for one route in, or PCNTRL. Reasonable, and you can use PHP from the command line.
3. Make other HTTP requests to yourself via CURL or similar, thus piggybacking on your web servers multi-processing capacity. Keeps all your code “web like”, but runs the risk of irate support developers tracking you down and breaking thumbs.

in PHP what does it mean by a function being binary-safe ?

It means the function will work correctly when you pass it arbitrary binary data (i.e. strings containing non-ASCII bytes and/or null bytes).

For example, a non-binary-safe function might be based on a C function which expects null-terminated strings, so if the string contains a null character, the function would ignore anything after it.

This is relevant because PHP does not cleanly separate string and binary data.

For instance, if PHP’s strlen function worked like C standard library strlen, the result here would be wrong:

如果函数是binary safe的话,我们将得到7;如果函数是非binary safe的话,我们将得到3 * strlen是binary safe的,所以实际上以下的运行结果是"7"
$str = "abc\x00abc";
echo strlen($str); //gives 7, not 3!

localization

原文: http://phpadvent.org/2010/localization-by-anthony-gentile
翻译:校长 RoyGu http://roygu.com

当我们创建一个网站时,一个非常重要的考虑是:网站的受众/访客。无论网站是销售商品、提供服务亦或是信息资讯,都须考虑当国外用户访问时页面如何呈现。如果他们想在你的网站上购买商品、使用服务或获取资讯,你的网站能够正常服务他们吗?应该提供正常服务吗?本地化让用户界面符合用户的预期,如:日期格式、货币以及本地语言文本。

许多以英语为母语的人并没有意识到这点,尽管英语的普及率很高,但说英语的人仍只占很小比率。这篇文章统计了世界上分布最广的语言是英语,但英语并不是人们说得最多的语言(现在排第三)。互联网上有如此多的有用信息,很大一部分不是用英文描述的。用计算机解决语言相关的问题是一件困难的事情,但是创建一个国际友好的网站并不是我们想象的那么难。虽然今天介绍的方法不能适用于10种不同语言的网站,但是对于需要提供两三种语言的网站非常有效果。比如,在美国,讲西班牙语的人数在显著增加,拥有一个能用西班牙语言交流的电子商务网站,将扩大你的潜在客户群。

在讲如何为网站实现本地化之前,我想花点时间谈论下字符编码。即使你无法预见你的网站是否需要提供本地化功能,了解字符(charsets)编码相关的知识都是非常有必要的。字符编码是用来帮助软件识别用户期望字符集的。例如,通用的ISO 8859-1字符集是西欧的通用字符集。因此,在这种字符集中可以用英文字母表示德语中的原音。但如果我在这种字符集中想显示可拉伯字符,如:ق,那么很可能会显示成� 或 Ù。这就意味着,在ISO 8859-1字符集下,不能正确识别阿拉伯字符。

一种非常友好的跨语言字符编码是兼容ASCII码的UTF-8编码,它代表Unicode字符集,特别是在传统应用中较为常见。在网站中使用UTF-8,其支持的字符非常多,能够最大地满足用户需求。为了正确地实现一种字符编码,你要确保在你整个应用中编码保持一致。如果你使用UTF-8,那么Apache、数据库、PHP以及PHP可用的功能和文档类型都应该设置成UTF-8。如果这些都不是一致的,你最终可能会得到不同字符编码的混合数据,这种问题即使能补救也比较困难。

// Apache httpd.conf or .htaccess

// This will add a charset to the Content-Type response header.
AddDefaultCharset UTF-8

// php.ini
default_charset = "UTF-8"

// Example PHP function
htmlentities($data, ENT_COMPAT, 'UTF-8');

// XML
<?xml version="1.0" encoding="UTF-8" ?>

// HTML
<meta http-equiv="Content-Type"
    content="text/html; charset=utf-8" />

如果你想了解更多关于UTF-8的内容,并且为什么它如此重要,猛击下面的链接:

刚才我们已经讨论了字符编码,接下来我们进入主题,谈谈如何实现本地化。如何判断为用户加载哪个本地化?如何知道用户来自哪里?一种解决方案是根据IP地址判断地域,但是更好的解决方案是让浏览器告诉我们使用哪个本地化。当用户发起HTTP请求时,HTTP头中的Accept-Language将会被发送,我们通常可以从PHP超全局变量$_SERVER中获取该值。看个示例:

Accept-Language: en-us;en;q=0.5

虽然这是一种检测默认语言的简单方法,但这并不意味着它就是用户期望的语言。所以提供一种简单方法给用户切换语言是非常有必要的。许多开发者认为,在session或cookie中存储本地化编码就足够了,但这种方法不够友好和直接,在URL中加入本地化提示岂不是更好,如:http://example.com/en/blog/http://example.com/de/blog; 或者用子域名来表示,如: http://en.wikipedia.org/.

如何实现呢?不难,在Apache中为网站设置一个重写规则:

RewriteRule ^(en|es)/(.*) /$2 [PT,E=lang:$1]

有了这个重写规则,我们就不需要为每种语言复制一份代码了。我们可以委托Apache查找用户请求的语言,并把它存储在环境变量中,然后转递到代码中。在我们的应用逻辑中,我们可以这样获取本地化编码:

$locale = apache_getenv('lang', true);

这里有一个支持本地化的PHP脚本,仅供参考:

<?php

/**
 * Stick to the codes that are already standard.
 * ISO 3166 - http://en.wikipedia.org/wiki/ISO_3166-1
 * RFC 1766 - http://www.faqs.org/rfcs/rfc1766.html
 */
$accepted_locales = array(

    'en' => 'en_US',
    'es' => 'es_MX'
);

// Get the locale from the browser.
$browser_locale = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);

// For more specific locale codes, e.g., en-us (English, United States), es-mx (Spanish, Mexican), etc.
// $browser_locale = current(explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']));

// Check against a whitelist instead of trusting $_GET['lang'].
// For reference: http://ha.ckers.org/blog/20100128/micro-php-lfi-backdoor/
if (in_array($browser_locale, array_keys($accepted_locales))) {
    $locale_code = $accepted_locales[$browser_locale];
} else {
    $locale_code = 'en_US';
}

// Or, use a URL-based locale designator and a rewrite rule.
// RewriteRule ^(en|es)/(.*) /$2 [PT,E=lang:$1]
// Then, grab that environment variable with PHP.
/*
$locale_code = apache_getenv('lang', true);
if (in_array($locale_code, array_keys($accepted_locales))) {
    $locale_code = $accepted_locales[$locale_code];
} else {
    $locale_code = 'en_US';
}
*/

$locale_entries = array();

// Load the locale file.
if (file_exists($locale_code . '.php')) {
    $locale_entries = include $locale_code . '.php';
}

/*
These locale entries are loaded from files that return an array.
en_US.php
<?php
return array(
    'WELCOME' => 'Hello %s!',
    'GOODBYE' => 'Goodbye!',
);

es_MX.php
<?php
return array(
    'WELCOME' => '¡Hola %s!',
    'GOODBYE' => '¡Adios!',
);

You could store locales in a database as well.
 */

// Now, you can create a simple function that will display the correct text.
function locale($locale_entries, $key, $replacements = array()) {
    if (isset($locale_entries[$key]) && empty($replacements)) {
        return $locale_entries[$key];
    } elseif (isset($locale_entries[$key])) {
        return vsprintf($locale_entries[$key], $replacements);
    }
    throw new Exception("Locale entry for '$key' does not exist.");
}

// echo locale($locale_entries, 'WELCOME', array('Anthony'));
// echo locale($locale_entries, 'GOODBYE');

// A basic class to handle locales
class Locale {

    public $code = 'en_US';
    public $locale_path = '/var/www/';
    protected $_entries = array();

    public function setCode($code)
    {
        $this->code = $code;
        $this->load();
    }

    public function load()
    {
        if (!file_exists($this->locale_path . $this->code . '.php')) {
            throw new Exception("Locale file: {$this->locale_path}{$this->code}.php does not exist.");
        }

        $this->_entries = include $this->locale_path . $this->code . '.php';
    }

    public function fetch($key, $replacements = array())
    {
        if (isset($this->_entries[$key]) && empty($replacements)) {
            return $this->_entries[$key];
        } elseif (isset($this->_entries[$key])) {
            return vsprintf($this->_entries[$key], $replacements);
        }
        throw new Exception("Locale entry {$this->code}:$key does not exist.");
    }
}

$locale = new Locale();
$locale->setCode($locale_code);

//echo $locale->fetch('WELCOME', 'Anthony');
//echo $locale->fetch('GOODBYE');

?>

我希望本文讲述得足够清楚了,能够帮助你养成思考网站访客并最大满足用户的好习惯。我认为绝大多数网站应该使用UTF-8。在项目开始阶段请至少花点时间确保网站是国际友好的。

原来method_exists等方法不区分大小写

今天突然回头想想刚开发完项目的新功能,好像我新增的action都是以双单词出现的,如:actionNewUser,但是在Router中只是简单的对URL中action做ucfirest(strtolower($action))处理,百思不得其解,这尼玛怎么就能找到该action呢? 但是事实往往是红果果的,经过测试发现method_exits和call_user_func_array等方法不区分方名法大小写。

千言万语不如上一图:

原来是我了解得不够,下次一定记得,哈哈,还大惊小怪的!!!!

一、大小写敏感
1. 变量名区分大小写
2. 常量名默认区分大小写,通常都写为大写
3. php.ini配置项指令区分大小写

二、大小写不敏感
1. 函数名、方法名、类名 不区分大小写,但推荐使用与定义时相同的名字
2. 魔术常量不区分大小写,推荐大写
3. NULL、TRUE、FALSE不区分大小写
4. 类型强制转换,不区分大小写,包括:
* (int),(integer) – 转换成整型
* (bool),(boolean) – 转换成布尔型
* (float),(double),(real) – 转换成浮点型
* (string) – 转换成字符串
* (array) – 转换成数组
* (object) – 转换成对象

PHP下载:解决中文文件名乱码

通过把Content-Type设置为application/octet-stream, 可以把动态生成的内容当作文件来下载,相信这个大家都会。 那么用Content-Disposition设置下载的文件名, 这个也有不少人知道吧。 基本上,下载程序都是这么写的:

<?php
$filename = "document.txt";
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);

print "Hello!";
?>

这样用浏览器打开之后,就可以下载document.txt。

但是,如果$filename是UTF-8编码的,有些浏览器就无法正常处理了。 比如把上面那个程序稍稍改一下:

<?php
$filename = "中文 文件名.txt";
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);

print "Hello!";
?>

把程序保存成UTF-8编码再访问,IE6下载的文件名就会乱码。 FF3下下载的文件名就只有“中文”两个字。Opera 9下一切正常。

输出的header实际上是这样子:

Content-Disposition: attachment; filename=中文 文件名.txt

其实按照RFC2231的定义, 多语言编码的Content-Disposition应该这么定义:

Content-Disposition: attachment; filename*="utf8''%E4%B8%AD%E6%96%87%20%E6%96%87%E4%BB%B6%E5%90%8D.txt"

即:

  • filename后面的等号之前要加 *
  • filename的值用单引号分成三段,分别是字符集(utf8)、语言(空)和urlencode过的文件名。
  • 最好加上双引号,否则文件名中空格后面的部分在Firefox中显示不出来
  • 注意urlencode的结果与php的urlencode函数结果不太相同,php的urlencode会把空格替换成+,而这里需要替换成%20

经过试验,发现几种主流浏览器的支持情况如下:

IE6 attachment; filename=”<URL编码之后的UTF-8文件名>”
FF3 attachment; filename=”UTF-8文件名”
attachment; filename*=”utf8”<URL编码之后的UTF-8文件名>”
O9 attachment; filename=”UTF-8文件名”

这样看来,程序必须得这样写才能支持所有主流浏览器:

<?php

$ua = $_SERVER["HTTP_USER_AGENT"];

$filename = "中文 文件名.txt";
$encoded_filename = urlencode($filename);
$encoded_filename = str_replace("+", "%20", $encoded_filename);

header('Content-Type: application/octet-stream');

if (preg_match("/MSIE/", $ua)) {
	header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
} else if (preg_match("/Firefox/", $ua)) {
	header('Content-Disposition: attachment; filename*="utf8\'\'' . $filename . '"');
} else {
	header('Content-Disposition: attachment; filename="' . $filename . '"');
}

print 'ABC';
?>