thinkphp 的主从数据库 链接资源分析

thinkphp 的主从数据库 链接资源分析

一主一丛

主 —负责数据的 插入,更新,删除
从 —负责数据的查询

操作的时候 通过 返回不同的 数据库链接来进行操作
下面是他的链接操作的代码

参数 $master 是关键

thinkphp 把默认的配置 的 第一个 ip 当作是主库, 其他的都是从库

如果是查询操作的时候,参数传递过来的永远是false , 根据下面的代码 他会 取得不同的配置文件 ,确定到底是链接那个数据库
[php]
protected function multiConnect($master=false) {
static $_config = array();
if(empty($_config)) {
// 缓存分布式数据库配置解析
foreach ($this->config as $key=>$val){
$_config[$key] = explode(‘,’,$val);
}
}
// 数据库读写是否分离
if(C(‘DB_RW_SEPARATE’)){
// 主从式采用读写分离
if($master) // ————————————- 这个地方应该是关键
// 默认主服务器是连接第一个数据库配置
$r = 0;
else
// 读操作连接从服务器
$r = floor(mt_rand(1,count($_config['hostname'])-1)); // 每次随机连接的数据库
}else{
// 读写操作不区分服务器
$r = floor(mt_rand(0,count($_config['hostname'])-1)); // 每次随机连接的数据库
}
$db_config = array(
‘username’ => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0],
‘password’ => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0],
‘hostname’ => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0],
‘hostport’ => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0],
‘database’ => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0],
‘dsn’ => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0],
‘params’ => isset($_config['params'][$r])?$_config['params'][$r]:$_config['params'][0],
);
return $this->connect($db_config,$r);
}

[/php]
永远 取得第一个数据库,是主数据库,
有点迷糊了, 有空在详细分析(相当不详细)

文章如转载,请注明:转载自:王志博-PHP[http://www.wangzhibo.com/]
本文链接地址:http://www.wangzhibo.com/?p=569

新浪微博Error_code: 400; Error: 40022:Error: source paramter(appkey) is missing的解决方法

老乡要用微博, 我在sina 官网下载的SDK , 娄了几眼, SDK 直接报错误.
看了下代码, 排除错误的解决方法
在调用statuses/public_timeline 获取最新的公共微博消息 的API出现Error_code: 400; Error: 40022:Error: source paramter(appkey) is missing的错误,终于还是解决了问题,原来是少了一条语句”source” => $consumer->key,

[php]
view plaincopy to clipboardprint?
public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
@$parameters or $parameters = array();
$defaults = array("source" => $consumer->key,//缺少的就是这条语句,加上即可
"oauth_version" => OAuthRequest::$version,
"oauth_nonce" => OAuthRequest::generate_nonce(),
"oauth_timestamp" => OAuthRequest::generate_timestamp(),
"oauth_consumer_key" => $consumer->key);
if ($token)
$defaults['oauth_token'] = $token->key;
$parameters = array_merge($defaults, $parameters);
return new OAuthRequest($http_method, $http_url, $parameters);
}
[/php]

可是在 官网直接下载的SDK 啊…
这个问题解决了, sina 的微博随便你自己怎么玩都行了.
文章如转载,请注明:转载自:王志博-PHP[http://www.wangzhibo.com/]
本文链接地址:http://www.wangzhibo.com/?p=566

ECSHOP 几个初始化设置简介

看ECSHOP 代码, 上来有几个初始化,我来说明下

memory_limit = 128M
; 一个脚本所能够申请到的最大内存字节数(可以使用K和M作为单位)。
; 这有助于防止劣质脚本消耗完服务器上的所有内存。
; 要能够使用该指令必须在编译时使用"--enable-memory-limit"配置选项。
; 如果要取消内存限制,则必须将其设为 -1 。
; 设置了该指令后,memory_get_usage()函数将变为可用。

----------------------------------------------------------------------------
session.cache_expire = 180
; 指定会话页面在客户端cache中的有效期限(分钟)
; session.cache_limiter=nocache时,此处设置无效。

----------------------------------------------------------

session.use_trans_sid = Off
; 是否使用明码在URL中显示SID(会话ID)。
; 默认是禁止的,因为它会给你的用户带来安全危险:
; 1- 用户可能将包含有效sid的URL通过email/irc/QQ/MSN...途径告诉给其他人。
; 2- 包含有效sid的URL可能会被保存在公用电脑上。
; 3- 用户可能保存带有固定不变sid的URL在他们的收藏夹或者浏览历史纪录里面。
; 基于URL的会话管理总是比基于Cookie的会话管理有更多的风险,所以应当禁用。

------------------------------------------------------------------------------------

session.use_cookies = On
; 是否使用cookie在客户端保存会话ID

----------------------------------------------------------------------------

session.auto_start = Off
; 在客户访问任何页面时都自动初始化会话,默认禁止。
; 因为类定义必须在会话启动之前被载入,所以若打开这个选项,你就不能在会话中存放对象。

----------------------------------------------------------------------------

display_errors = On
; 是否将错误信息作为输出的一部分显示。
; 在最终发布的web站点上,强烈建议你关掉这个特性,并使用错误日志代替(参看下面)。
; 在最终发布的web站点打开这个特性可能暴露一些安全信息,
; 例如你的web服务上的文件路径、数据库规划或别的信息。

例子:
/* 初始化设置 */
@ini_set('memory_limit',          '64M');
@ini_set('session.cache_expire',  180);
@ini_set('session.use_trans_sid', 0);
@ini_set('session.use_cookies',   1);
@ini_set('session.auto_start',    0);
@ini_set('display_errors',        1);

文章如转载,请注明:转载自:王志博-PHP[http://www.wangzhibo.com/]
本文链接地址:http://www.wangzhibo.com/?p=563

突破高原反应, 成为PHP 方向的一个合格的架构师

突然看到这篇文章, 值得反省, 乐在其中, 在接下来的发展中不被淘汰的都来看看,

如何成为一个架构师
先明确这里所指的PHP工程师,是指主要以PHP进行Web系统的开发,没有使用其的语言工作过。工作经验大概在3~4年,普通的Web系统(百万级访问,千成级数据以内或业务逻辑不是特别复杂)开发起基本得心应手,没有什么问题。但他们会有这样的误点:

◆ 除了PHP不使用其它的语言,可能会点shell 脚本。

◆ 对PHP的掌握不精(很多PHP手册都没有看完,库除外)。

◆ 知识面比较窄(面对需求,除开使用PHP和MYSQL,不知道其它的解决办法)。

◆ PHP代码以过程为主,认为面向对象的实现太绕,看不懂。

这些PHPer在遇到需要高性能,处理高并发,大量数据的项目或业务逻辑比较复杂(系统需要解决多领域业务的问题)时,缺少思路。不能分析问题的本质,技术判断力比较差,对于问题较快能找出临时的解决办法,但常常在不断临时性的解决办法中,系统和自己一步步走向崩溃。那怎么提高自己呢?怎么可以挑战难度更高的系统?

更高的挑战在那里?

结合我自己的经验,我列出一些具体挑战,让大家先有个感性的认识。

高性能系统的挑战在那里?

◆ 如何选择Web服务器?要不要使用fast-cgi 模式;

◆ 要不要使用反向代理服务?选择全内存缓存还是硬盘缓存?

◆ 是否需要负载均衡?是基于应用层,还是网络层? 如何保证高可靠性?

◆ 你的PHP代码性能如何,使用优化工具后怎么样? 性能瓶颈在那里? 是否需要写成C的扩展?

◆ 用户访问有什么特点,是读多还是写多?是否需要读写分离?

◆ 数据如何存储?写入速度和读出速度如何? 数据增涨访问速读如何变化?

◆ 如何使用缓存? 怎么样考虑失效?数据的一致性怎么保证?

高复杂性系统的挑战在那里?

◆ 能否识别业务所对应的领域?是一个还是多个?

◆ 能否合理对业务进行抽象,在业务规则变化能以很小的代价实现?

◆ 数据的一致性、安全性可否保证?

◆ 是否撑握了面向对象的分析和设计的方法?

这里所列出的问题,你都能肯定的回答,说明在技术上你基本已经可能成为架构师了。如何你还不能回答,你需要在以下几个方向加强。

怎么样提高,突破瓶颈

如何你还不能回答,你需要在以下几个方向加强:

◆ 分析你所使用的技术其原理和背后运行的机制,这样可以提高你的技术判断力,提高你技术方案选择的正确性;

◆ 学习大学期间重要的知识,操作系统原理,数据结构和算法。知道你以前学习都是为了考试,但现在你需要为自己学习,让自己知其所以然;

◆ 重新开始学习C语言,虽然你在大学已经学过。这不仅是因为你可能需要写PHP扩展,而且还因为,在做C的应用中,有一个时刻关心性能、内存控制、变量生命周期、数据结构和算法的环境;

◆ 学习面向对象的分析与设计,它是解决复杂问题的有效的方法。学习抽象,它是解决复杂问题的唯一之道。

看完这个文章,大家思考一下, 志博预祝大家早日成为一名PHP 架构师 team leader
文章如转载,请注明:转载自:王志博-PHP[http://www.wangzhibo.com/]
本文链接地址:http://www.wangzhibo.com/?p=556

代码的意义, 多读读把

很不错的文章, 推荐下, 志博在此文章发现了很多
原文:Why I Love Reading Other People’s Code And You Should Too by Alan Skorkin翻译:Yurii
我发现,许多程序员都讨厌读代码——拜托别掩饰了,承认吧。差不多每个人都喜欢写代码——写代码乐在其中。可是,读代码真是不容易,而且还很烦人,又无可逃避,其他人写的代码总是很垃圾(即便不说,我们心里也这么想的)。即使自己写的代码,过几个小时再看也有点垃圾,过的时间再久点,就更垃圾了。那么,还有什么理由去看别人的蹩脚代码,而是不自己写几手漂亮的?能不能暂且忽略这个问题,花上几个小时看别人的代码,再回头来看自己的是不是还那么漂亮?即便有位大师坐在你面前,如果你不能从他身上学习,你永远也成不了大师。办法之一就是找到这么一位大师,让他手把手地教会你全部知识。有这可能吗?——当然有,只是很难遇到这顶好的运气。不过你也不必奢求那么幸运,做程序员这行就很幸运,因为大师们的所有思想和技艺都凝铸在他们的代码里,供我们学习。你要做的只是阅读代码——当然,如果有人给你一点点地讲肯定更节省时间,但这基本属于痴人说梦。换句话说,要相当个好木匠,得仔细研究大量的精美家具。
我热爱读代码,我总是直观地认为读代码的收获很大,没错,它可能有点讨厌甚至烦人,但你的收益绝对大过这点麻烦。举个例子,你要当大作家,是不是只关心自己写东西就够了?你可以试试看,但是估计不会折腾不出什么名堂。公认的事实是,多数大作家都是会如饥似渴大量阅读的。想写出好的作品,必须先阅读其他大作家的作品,吸收不同的风格,了解他人的尝试,然后才可以培养自己的创造力。这样,你的知识才能逐渐积累,最终你写的东西才有几分成熟,你也才会找到“感觉”。写代码也是这样,如果你不去阅读那些伟大的代码,怎么可能把程序写的漂亮?阅读伟大的代码之于程序员,就如同阅读伟大作品之于作家(我不敢掠美,这句话是Peter Norvig(译注:Peter Norvig是著名的Lisp程序员,现任Google研发总监)说的,他可不是个简单人物,所以好好记住这句话吧)。
即使上面说的你都不信,但有个事实无可否认。要想当个称职的开发人员,能熟练阅读代码是非常重要的。如今,只要不是闹着玩的项目,都是团队协作的成果,所以总会有这样的代码:它不是你写的,但你必须跟它打交道,去修改,或者去扩展。于是,阅读代码很可能就是你身上最重要最常用的能力了,咬紧牙关练好这门本事吧——而且,要快。
要像…会读代码的那些家伙一样…阅读代码
我都说不清有多少次见过这样的事情了:程序员把一段不熟悉的代码上下拖动,几分钟之后仍然一脸迷离。不久他们就宣布,这段代码根本没法看懂,更不必浪费时间了,可以想办法绕过这个问题。我不知道他们真正要做的是什么,一点点弄明白这段代码的意思,还是睁大眼睛等着开窍?阅读代码不靠成年累月死盯着看,你要做的是弄懂它,把它变成自己的。下面说的是我用的一些技巧,但不是全部,不过我觉得这些非常有用。

看代码看到目光迷离
1. 尝试亲自构建和运行程序。通常这一步很容易做到,比如你看的是真正运行的工作代码时(而不是不知来源的古怪代码)就是如此。不过也不是每次都很容易,如果不能很容易地构建和运行,你可以在完成构建和运行的过程中,认识到代码的高层结构。而且,阅读工作代码,你会非常熟悉如何构建项目。构建通常是复杂的,但是了解构建过程,知道代码是如何变为可执行程序的,会大大加深你的理解。
2. 别死盯细节。读代码要做的第一件事,是找到对代码的结构和风格的感觉。开始应当浏览,并且努力找出各部分代码都在干什么。这样你能熟悉整套代码的高层结构,也会明白你正在看的是什么样的代码(重构良好的,还是乱成一团的)。这时候你要做的就是找到入口(可能是main函数,也可能是servlet,controller之类),看看下面的分支是怎么展开的。这一步不要花太多时间,你对全部代码更熟悉之后,随时可以退回来。
3. 确保理解所有构造(construct)。除非你非常精通这门编程语言,否则多半还有些东西是你不知道的。在概略了解代码的阶段,要记下每一个不熟悉的构造。如果这样的构造有很多,下一步就不言自明了。如果搞不懂代码行为的意义,你什么也干不了。即便你不熟悉的只是少数构造,仔细观察推敲没准也是好事。你可能会找到一些以前不知道的关于这门编程语言的知识,我就很乐意为此花上几个小时。
4. 待熟悉了大多数构造之后,就可以搞几次随机的深入探查了。做法类似第2步,快速浏览代码库,但是这次要随机抽几个函数或者类,一行行地看下去。真正的考验现在才开始,但你的收益也是从这一步开始显现。主旨是:真正深入到你所阅读的整套代码的概念体系(组件结构)当中。这又是一个速度快不起来的步骤,但是在这一步,一定要尝试深入理解若干繁杂的细节。和第2步一样,在这一步,每次你多了解了一些上下文再回头看看,你的理解就更深入一些。
5. 前几步中肯定还有你不明白的地方,现在最合适的就是跑几个测试,看看已有的测试。测试很可能会大大打消你的疑惑,加深你对所测试代码的理解。我时常不能理解,为什么有些开发人员在阅读和理解代码时,忽略严密而精巧的测试套件。当然,也有时候是因为没有测试程序。
6. 如果没有测试程序,这时候就该写上几个。这样做有很多好处,它会加深自己的理解,它可以完善整个代码库,在阅读代码的时候也在写代码,这样对已有代码和你都有好处,你也可以真正动手参与进去。即便有现成的测试程序,为了加深自己的理解,你也可以再写一些。测试人家的代码,一般要求换个角度思考,之前你感到迷惑的概念也会变得更清楚。
7. 把弄不懂的部分拿到单独的程序中来。我发现,读代码时这样做,哪怕只是为了调节阅读的节奏,也是非常有乐趣的。即使你不理解代码的底层细节,也可能会对代码的功能有些高层面的想法。那为什么不把一些功能抽到单独的程序中测试呢?如果只运行一小段程序,debug就容易多了,而且这样的过程反过来又会加深你的理解。
8. 代码很乱(dirty)很糟糕(smelly)?那么重构吧。我可不是建议你把整个代码库推倒重来,但是重构一些部分确实可以让你的理解更上层楼。一开始要做的是把你明白了的功能变为独立的函数。在你真正理解之前,重构之前的函数只是看起来没问题,而重构可以把它们变成你想要的样子。依靠重构,你可以把代码变成自己的,而不要全部重写。好的测试程序可以帮上忙,不过如果你没有,就一边测试一边重构吧,而且只改动那些你确认弄懂了的功能。即便测试看起来太少太不完善,也要相信你自己的开发水平,有时候你只管大胆尝试就好(如果确实需要,总是可以回退(revert)的)。
9. 如果上面说的都不管用,就找个同伴跟你一起读代码。能从读代码中受益的可能并不只有你一个人,所以不妨抓住其他人,一起阅读。不过别找专家,他们给你的解释都是高层面的,这样看代码时注意的那些细节就都被忽略了。如果找不到人一起阅读,你又实在看不懂,有时最好的办法就是问别人。可以问你的同事,如果你在读的代码是开源的,也可以在网上问问其他人。记住,这只是最后的办法,不要一开始就这么做。
如果时间很紧张,短时间内必须弄懂某些代码,上面的步骤中只能选一步,我会选择重构(第8步)。你可能没法明白太多东西,但你肯定可以理解真正动过的部分。无论时间是不是紧张,你要记住的是:如果你第一次接触重要的代码库,肯定不能一下子就看懂,甚至不可能很快看懂。你可能需要耐心读上几天,几周甚至几个月——坦然面对就好。即便有专家坐在你身边,也省不了太多时间(我写的关于教和学的系列文章最后一篇就会谈这个问题)。如果你读(或者写)代码的耐心足够,方法得当,你肯定能成为对项目所有方面都非常熟悉的人,也是大家对代码库有问题时出面解答问题的人。你也可以不阅读代码,选择成为那个总想找人来解释的家伙。我想要做哪样的人,我自己很清楚。
抓住阅读代码的机会,别错过

我们都喜欢新写代码,它的诱惑力在于,我们能搞定问题。起码,这次搞不定,下次可以搞定。真相是:你在实践中不断提高,永远不可能一下就彻底搞定。这就是新写代码的价值所在,你在练习,你的水平在提高,但是阅读和改动其他人写的代码也很有价值(至少不亚于自己重新写),从中你学习到的不光是有价值的技术知识,还有关于整个工作领域的知识(毕竟,代码才是文档的最终形式),这种知识通常更有价值。
每一段不遵循传统的,莫测难懂的代码,都是有价值的。你知道我说的是什么,虽然它看起来一团糟,但本意并非如此(也可能因为它是Perl代码:))。每次我看到这样的代码,我都这么想。不妨把阅读它当作猜谜游戏,想想你能学到什么。是的,这很折磨人,但必须承认,你也希望能动手就能写出这么糟糕的代码。如果你花时间阅读这样的代码,你肯定更可能写出这样的代码——这倒不是说,你一定会写这样的代码,但你肯定希望自己能够。最后要说的是,态度总是非常重要的。如果你把阅读代码看作闲杂事,那它就是闲杂事,而你肯定会逃避,但是如果你把它看成机会,事情就不一样了。

文章如转载,请注明:转载自:王志博-PHP[http://www.wangzhibo.com/]
本文链接地址:http://www.wangzhibo.com/?p=549

获取客户端IP 的一个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
function get_client_ip(){
if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown"))
$ip = getenv("HTTP_CLIENT_IP");
else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown"))
$ip = getenv("HTTP_X_FORWARDED_FOR");
else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown"))
$ip = getenv("REMOTE_ADDR");
else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown"))
$ip = $_SERVER['REMOTE_ADDR'];
else
$ip = "unknown";
return($ip);
}

文章如转载,请注明:转载自:王志博-PHP[http://www.wangzhibo.com/]
本文链接地址:http://www.wangzhibo.com/?p=549

让 网页的 title 不停的闪动

一段js 代码, 让网页的title 不停的闪动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh" lang="zh" dir="ltr">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link rel="shortcut icon" href="images/favicon.ico" />
    <title>title 不停的闪动</title>
<script language="JavaScript">
var step=0;  
function changetitle(){
  step++;  
  if (step==3) {step=1};  
  if (step==1) {document.title='标题一'};
  if (step==2) {document.title='标题二'}; 
  setTimeout("changetitle()",1000);
}
changetitle();  //调用函数自身
</script>
 
</head>
<body >
 
</body>
</html>

文章如转载,请注明:转载自:王志博-PHP[http://www.wangzhibo.com/]
本文链接地址:http://www.wangzhibo.com/?p=547

城市包围农村,占着茅坑不拉屎的发展道路.

今天翻看我原来的记事本,看到了我2 年前的一个工作的日志。 记录了那天我想干的事情,去申请一些地区性的网站.
可是当初不知道什么原因这些域名没有申请,现在想申请 这些域名都让别人给申请了… 郁闷..
最近也考虑了很多 ,2 年前我发展 地区性的 想法 没有去实施, 2年后的今天还是没有实施 … 不知道我到底还在等什么?
如果在不行动的话,
真的连个茅坑都占不到了… …

文章如转载,请注明:转载自:王志博-PHP[http://www.wangzhibo.com/]
本文链接地址:http://www.wangzhibo.com/?p=543

jquery 写的一个简单的 三级联动的例子

下午翻代码,看到之前写的一个JS ,三级联动的例子

    $(function() {
        $('#country_01').change(function() {
            selectCountry();
        });

        $("#country_02").change(function() {
            selectProvince();
        });

        $("#country_03").change(function() {
            selectCity();
        })
    });
    function selectCountry() {
        var country_01_id = $('#country_01').val();         //获得国家的值
            test(country_01_id);
            if (!(country_01_id == '请选择国家')) {
                $.ajax({
                type: "POST",               // 传递的类型
                url: "?c=area&a=getcountry",       //传递的URL
                data: "country_01_id="+country_01_id,
                dataType:'JSON',
                success: function(cityList)//如果成功执行的函数
                {
                    $("#country_02").empty();
                    var opt = '<option value=请选择省份>请选择省份</option>';
                    var cityList = eval("("+cityList+")");
                    var cityCount = cityList.length;
                    for (var i=0; i<cityCount; i++) {
                         opt += "<option value="+cityList[i]['id']+">"+cityList[i]['region_name']+"</option>";
                    }
                    $("#country_02").append(opt);
                }
            });
            }
    }

    function selectProvince() {
        var country_02_id = $('#country_02').val();
            test(country_02_id);
            if (!(country_02_id == '请选择省份')) {
                $.ajax({
                type: "POST",               // 传递的类型
                url: "?c=area&a=getcity",       //传递的URL
                data: "country_02_id="+country_02_id,
                dataType:'JSON',
                success: function(cityList)//如果成功执行的函数
                {
                    $("#country_03").empty();
                    var opt = "<option value='请选择城市'>请选择城市</option>";
                    var cityList = eval("("+cityList+")");
                    var cityCount = cityList.length;
                    for (var i=0; i<cityCount; i++) {
                         opt += "<option value="+cityList[i]['id']+">"+cityList[i]['region_name']+"</option>";
                    }
                    $("#country_03").append(opt);
                    $("#country_04").empty();
                $("#country_04").append("<option value='请选择县区'>请选择县区</option>");
                }
            });
        }
    }

    function selectCity() {
        var country_03_id = $('#country_03').val();
            test(country_03_id);
            if (!(country_03_id == '请选择城市')) {
                $.ajax({
                type: "POST",               // 传递的类型
                url: "?c=area&a=getLast",       //传递的URL
                data: "country_03_id="+country_03_id,
                dataType:'JSON',
                success: function(cityList)//如果成功执行的函数
                {
                    $("#country_04").empty();
                    var opt = "<option value='请选择县区'>请选择县区</option>";
                    var cityList = eval("("+cityList+")");
                    var cityCount = cityList.length;
                    for (var i=0; i<cityCount; i++) {
                         opt += "<option value="+cityList[i]['id']+">"+cityList[i]['region_name']+"</option>";
                    }
                    $("#country_04").append(opt);
                }
            });
        }
    }

        /*
        *如果选择初始值,全部返回原样
        *@param 每个分类的ID
        *@date 2010-8-30
        *@author tarfly
        */
        function test(country_id) {
            if (country_id == '请选择国家') {
                $("#country_02").empty();
                $("#country_02").append("<option value='请选择省份'>请选择省份</option>");
                $("#country_03").empty();
                $("#country_03").append("<option value='请选择城市'>请选择城市</option>");
                $("#country_04").empty();
                $("#country_04").append("<option value='请选择县区'>请选择县区</option>");
            }
            if (country_id == '请选择省份') {
                $("#country_03").empty();
                $("#country_03").append("<option value='请选择城市'>请选择城市</option>");
                $("#country_04").empty();
                $("#country_04").append("<option value='请选择县区'>请选择县区</option>");
            }
            if (country_id == '请选择城市') {
                $("#country_04").empty();
                $("#country_04").append("<option value='请选择县区'>请选择县区</option>");
            }
        }

文章如转载,请注明:转载自:王志博-PHP[http://www.wangzhibo.com/]
本文链接地址:http://www.wangzhibo.com/?p=541

php stat() 函数 解析

看ECSHOP ,缓存机制看到 这样一个目录函数:

1
2
3
4
5
6
7
8
9
10
foreach ($para['template'] AS $val)
                {
                    $stat = @stat($val);// 函数获得文件信息
                    if ($para['maketime'] &lt; $stat['mtime'])   // 判断文件是否过期 
                    {
                        $this-&gt;caching = false;
 
                        return false;
                    }
                }

stat(‘filepath’) filepath 是文件的路径, 返回传入文件的信息:

The stat() function returns information about a file.
stat()函数的作用是:返回一个文件的信息。

This function returns an array with the following elements:
这个函数将返回一个包含下列元素的数组:

[0] or [dev] - Device number
[0] 或 [dev] –代表(驱动)设备的数字
[1] or [ino] - Inode number
[1] 或 [ino] – 代表Inode的数字
[2] or [mode] - Inode protection mode
[2] 或 [mode] – Inode保护模式
[3] or [nlink] - Number of links
[3] 或 [nlink] –代表连接的数字
[4] or [uid] - User ID of owner
[4] 或 [uid] – 拥有者的用户id[User ID]
[5] or [gid] - Group ID of owner
[5] 或 [gid] – 拥有者的群id[Group ID]
[6] or [rdev] - Inode device type
[6] 或 [rdev] – Inode设备类型
[7] or [size] - Size in bytes
[7] 或 [size] – 字节数大小
[8] or [atime] - Last access (as Unix timestamp)
[8] 或 [atime] – 最后一次访问(Unix时间戳[timestamp])
[9] or [mtime] - Last modified (as Unix timestamp)
[9] 或 [mtime] -最后一次修改(Unix时间戳[timestamp])
[10] or [ctime] - Last inode change (as Unix timestamp)
[10] 或 [ctime] -最后一次修改inode(Unix时间戳[timestamp])
[11] or [blksize] - Blocksize of filesystem IO (if supported)
[11] 或 [blksize] – 文件系统IO的区域大小[Blocksize of filesystem IO](必须在支持这个元素的情况下)
[12] or [blocks] - Number of blocks allocated
[12] 或 [blocks] – 指派的空间数量

文章如转载,请注明:转载自:王志博-PHP[http://www.wangzhibo.com/]
本文链接地址:http://www.wangzhibo.com/?p=537

总结2010 ,展望2011

2010 精彩,充满 回味… …
2011 给力,充满 期待… …

学到了很多,明白了很多, 人生道路上添加了 一笔重要的财富!

学到了什么 — 网站的架构, mysql 主从分离, 网站优化, 提供jquery 能力 …
明白了什么 — 没有任何人值得可怜,理解,除了自己的父母,亲人,还有爱你的人和你爱的人, 对他人只有利益 … 我不说你们懂的。
该去做什么 — 把我的所有都给我上面提到的人, 还有我的工作, 提高自己的优化,负载,处理问题的能力

别的不多说了, 妥妥的, 你懂的!

王志博 与 2010年12月31日 23:38

生成xml ,注意事项. XML特殊符号

写一个图片轮播功能: 上传图片,然后生成xml, flash 操作xml ,控制图片;
xml 格式如下:

<images>
<image src='/Uploads/flash/4d1c2eae7f91d.jpg' url='http://www.wangzhibo.com?id=1&test=2'/>
<image src='/Uploads/flash/4d1c2eae7f91d.jpg' url='http://www.wangzhibo.com?id=1&test=2'/>
<image src='/Uploads/flash/4d1c2eae7f91d.jpg' url='http://www.wangzhibo.com?id=1&test=2'/>
</images>

php 拼接字符串,生成XML , url 里面存在 & 符合, 需要 把 xml 转化成 &amp,
[php]
str_replace(‘&’,'&amp;’,$str);
[/php]
查了下资料, 找的 需要转换的 特殊字符

< < 小于号
> > 大于号
& & 和
' ‘ 单引号
" ” 双引号

注意: 只有”<" 字符和"&"字符对于XML来说是严格禁止使用的。剩下的都是合法的,为了减少出错,使用实体是一个好习惯。

文章如转载,请注明:转载自:王志博-PHP[http://www.wangzhibo.com/]
王志博

【转】mysql replication 基本原理,mysql主从配置原理

mysql replication 基本原理,mysql主从配置原理
1、复制进程
Mysql的复制(Replication)是一个异步的复制,从一个Mysql instace(称之为Master)复制到另一个Mysql instance(称之Slave)。实现整个复制操作主要由三个进程完成的,其中两个进程在Slave(Sql进程和IO进程),另外一个进程在 Master(IO进程)上。
要实施复制,首先必须打开Master端的binary log(bin-log)功能,否则无法实现。因为整个复制过程实际上就是Slave从Master端获取该日志然后再在自己身上完全顺序的执行日志中所记录的各种操作。
复制的基本过程如下:
1)、Slave上面的IO进程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;

2)、 Master接收到来自Slave的IO进程的请求后,通过负责复制的IO进程根据请求信息读取制定日志指定位置之后的日志信息,返回给Slave 的IO进程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置;

3)、 Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的 bin-log的文件名和位置记录到master-info文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log的哪个位置开始往后的日志内容,请发给我”;

4)、Slave的Sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,并在自身执行。
实际上在老版本的Mysql的复制实现在Slave端并不是两个进程完成的,而是由一个进程完成。但是后来发现这样做存在较大的风险和性能问题,主要如下:
首先,一个进程就使复制bin-log日志和解析日志并在自身执行的过程成为一个串行的过程,性能受到了一定的限制,异步复制的延迟也会比较长。
另外,Slave端从Master端获取bin-log过来之后,需要接着解析日志内容,然后在自身执行。在这个过程中,Master端可能又产生了大量变化并声称了大量的日志。如果在这个阶段Master端的存储出现了无法修复的错误,那么在这个阶段所产生的所有变更都将永远无法找回。如果在Slave 端的压力比较大的时候,这个过程的时间可能会比较长。
所以,后面版本的Mysql为了解决这个风险并提高复制的性能,将Slave端的复制改为两个进程来完成。提出这个改进方案的人是Yahoo!的一位工程师“Jeremy Zawodny”。这样既解决了性能问题,又缩短了异步的延时时间,同时也减少了可能存在的数据丢失量。当然,即使是换成了现在这样两个线程处理以后,同样也还是存在slave数据延时以及数据丢失的可能性的,毕竟这个复制是异步的。只要数据的更改不是在一个事物中,这些问题都是会存在的。如果要完全避免这些问题,就只能用mysql的cluster来解决了。不过mysql的cluster是内存数据库的解决方案,需要将所有数据都load到内存中,这样就对内存的要求就非常大了,对于一般的应用来说可实施性不是太大。

2、复制实现级别
Mysql的复制可以是基于一条语句(Statement level),也可以是基于一条记录(Row level),可以在Mysql的配置参数中设定这个复制级别,不同复制级别的设置会影响到Master端的bin-log记录成不同的形式。
Row Level:日志中会记录成每一行数据被修改的形式,然后在slave端再对相同的数据进行修改。
优点:在row level模式下,bin-log中可以不记录执行的sql语句的上下文相关的信息,仅仅只需要记录那一条记录被修改了,修改成什么样了。所以row level的日志内容会非常清楚的记录下每一行数据修改的细节,非常容易理解。而且不会出现某些特定情况下的存储过程,或function,以及 trigger的调用和触发无法被正确复制的问题。
缺点:row level下,所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,这样可能会产生大量的日志内容,比如有这样一条update语句:update product set owner_member_id = ‘b’ where owner_member_id = ‘a’,执行之后,日志中记录的不是这条update语句所对应额事件(mysql以事件的形式来记录bin-log日志),而是这条语句所更新的每一条记录的变化情况,这样就记录成很多条记录被更新的很多个事件。自然,bin-log日志的量就会很大。尤其是当执行alter table之类的语句的时候,产生的日志量是惊人的。因为Mysql对于alter table之类的表结构变更语句的处理方式是整个表的每一条记录都需要变动,实际上就是重建了整个表。那么该表的每一条记录都会被记录到日志中。
Statement Level:每一条会修改数据的sql都会记录到 master的bin-log中。slave在复制的时候sql进程会解析成和原来master端执行过的相同的sql来再次执行。
优点:statement level下的优点首先就是解决了row level下的缺点,不需要记录每一行数据的变化,减少bin-log日志量,节约IO,提高性能。因为他只需要记录在Master上所执行的语句的细节,以及执行语句时候的上下文的信息。
缺点:由于他是记录的执行语句,所以,为了让这些语句在slave端也能正确执行,那么他还必须记录每条语句在执行的时候的一些相关信息,也就是上下文信息,以保证所有语句在slave端杯执行的时候能够得到和在master端执行时候相同的结果。另外就是,由于Mysql现在发展比较快,很多的新功能不断的加入,使mysql得复制遇到了不小的挑战,自然复制的时候涉及到越复杂的内容,bug也就越容易出现。在statement level下,目前已经发现的就有不少情况会造成mysql的复制出现问题,主要是修改数据的时候使用了某些特定的函数或者功能的时候会出现,比如:sleep()函数在有些版本中就不能真确复制,在存储过程中使用了last_insert_id()函数,可能会使slave和master上得到不一致的id等等。由于row level是基于每一行来记录的变化,所以不会出现类似的问题。
从官方文档中看到,之前的Mysql一直都只有基于statement的复制模式,直到5.1.5版本的Mysql才开始支持row level的复制。从5.0开始,Mysql的复制已经解决了大量老版本中出现的无法正确复制的问题。但是由于存储过程的出现,给Mysql的复制又带来了更大的新挑战。另外,看到官方文档说,从5.1.8版本开始,Mysql提供了除Statement Level和Row Level之外的第三种复制模式:Mixed,实际上就是前两种模式的结合。在Mixed模式下,Mysql会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种。新版本中的Statment level还是和以前一样,仅仅记录执行的语句。而新版本的Mysql中队row level模式也被做了优化,并不是所有的修改都会以row level来记录,像遇到表结构变更的时候就会以statement模式来记录,如果sql语句确实就是update或者delete等修改数据的语句,那么还是会记录所有行的变更。

3、复制常用架构
Mysql复制环境90%以上都是一个Master带一个或者多个Slave的架构模式,主要用于读压力比较大的应用的数据库端廉价扩展解决方案。因为只要master和slave 的压力不是太大(尤其是slave端压力)的话,异步复制的延时一般都很少很少。尤其是自slave端的复制方式改成两个进程处理之后,更是减小了 slave端的延时。而带来的效益是,对于数据实时性要求不是特别的敏感度的应用,只需要通过廉价的pc server来扩展slave的数量,将读压力分散到多台slave的机器上面,即可解决数据库端的读压力瓶颈。这在很大程度上解决了目前很多中小型网站的数据库压力瓶颈问题,甚至有些大型网站也在使用类似方案解决数据库瓶颈。
一个Master带多个slave的架构实施非常简单,多个slave 和单个slave的实施并没有太大区别。在Master端并不care有多少个 slave连上了master端,只要有slave进程通过了连接认证,向他请求binlog信息,他就会按照连接上来的io进程的要求,读取自己的 binlog信息,返回给slave的IO进程。对于slave的配置细节,在Mysql的官方文档上面已经说的很清楚了,甚至介绍了多种实现slave 的配置方法。
Mysql不支持一个Slave instance从属于多个Master的架构。就是说,一个slave instance只能接受一个master的同步源,听说有patch可以改进这样的功能,但没有实践过。Mysql AB之所以不实现这样的功能,主要是考虑到冲突解决的问题。
Mysql也可以搭建成dual master模式,也就是说两个Mysql instance互为对方的Master,也同时为对方的Slave。不过一般这种架构也是只有一端提供服务,避免冲突问题。因为即使在两边执行的修改有先后顺序,由于复制的异步实现机制,同样会导致即使在晚做的修改也可能会被早做的修改所覆盖,就像如下情形:
时间点 Mysql A Mysql B
1 更新x表y记录为10
2 更新x表y记录为20
3 获取到A日志并应用,更新x表的y记录为10(不符合期望)
4 获取B日志更新x表y记录为20(符合期望)
这样,不仅在B库上面的数据不是用户所期望的结果,A和B两边的数据也出现了不一致的情况。除非能将写操作根据某种条件固定分开在A和B两端,保证不会交叉写入,才能够避免上面的问题。

把网页放到桌面

项目需要这样一个功能, 把首页 放到桌面,然后生成一个快捷方式
[html]
<html>
<head>
<title>把我的Blog放到首页</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
</head>
<body>
<a href=’tarfly.php’>王志博-【PHP研发,致力于PHP最前沿】</a>
</body>
</html>
[/html]
[html]
<?php
$Shortcut = "[DEFAULT]
BASEURL=http://www.wangzhibo.com/
[InternetShortcut]
URL=http://www.wangzhibo.com
IDList=
IconFile=http://www.wangzhibo.com/favicon.ico
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
";
header(‘Content-Type: application/octet-stream’);
header("Content-Disposition: attachment; filename=王志博-【PHP研发,致力于PHP最前沿】.url");
echo $Shortcut;
?>
[/html]

这样就可以把 网页变成快捷方式了!
但是存在一个问题, 如果保存名称是中文的话 弹出下载会显示乱码, 我会在下面的文章里面写出找到的解决方法!
王志博 2010/12/06 13:29

InnoDB和MyISAM区别总结

MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。 MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。综述,就可以根据数据表不同的用处是用不同的存储类型。而且MyISAM是文件存储的,可以进行直接在不同操作系统间拷贝使用。

InnoDB

InnoDB 给 MySQL 提供了具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。InnoDB 提供了行锁(locking on row level),提供与 Oracle 类型一致的不加锁读取(non-locking read in SELECTs)。这些特性均提高了多用户并发操作的性能表现。

在InnoDB表中不需要扩大锁定(lock escalation),因为 InnoDB 的列锁定(row level locks)适宜非常小的空间。InnoDB 是 MySQL 上第一个提供外键约束(FOREIGN KEY constraints)的表引擎。InnoDB 的设计目标是处理大容量数据库系统,它的 CPU 利用率是其它基于磁盘的关系数据库引擎所不能比的。在技术上,InnoDB 是一套放在 MySQL 后台的完整数据库系统,InnoDB 在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。

InnoDB 把数据和索引存放在表空间里,可能包含多个文件,这与其它的不一样,举例来说,在 MyISAM 中,表被存放在单独的文件中。InnoDB 表的大小只受限于操作系统的文件大小,一般为 2 GB。InnoDB所有的表都保存在同一个数据文件 ibdata1 中(也可能是多个文件,或者是独立的表空间文件),相对来说比较不好备份,可以拷贝文件或用navicat for mysql。

MyISAM

每张MyISAM 表被存放在三个文件 :frm 文件存放表格定义。 数据文件是MYD (MYData) 。 索引文件是MYI (MYIndex) 引伸。
因为MyISAM相对简单所以在效率上要优于InnoDB,小型应用使用MyISAM是不错的选择。
MyISAM表是保存成文件的形式,在跨平台的数据转移中使用MyISAM存储会省去不少的麻烦

王志博 22.37