自动更新@version $Id$版本号信息(subversion svn:keywords)
在一些开源项目的文件注释中,经常会见到一串类似“@version $Id: Result.php 20096 2010-01-06 02:05:09Z bkarwin $”的字符信息。它描述的是该文件当前的综合版本信息,方便我们了解更多该文件的历史信息。
以上字符串中,前面的“@version”为注释文档(如:JAVADoc,PHPDoc)的版本字段,后面的则是SVN中的版本信息。那么,这些信息是如何更新的呢?不至于手工一个个编辑吧,那每次更新前还要查一下修订号多麻烦。
答案当然不是,大多的版本控制软件都提供了该功能。在用户提交代码是,版本控制软件自动更新你的标注。在subversion中提供了一个svn:keywords的命令,通过该命令可以更新代码中标注的关键字,以包含最新的相关信息(如:修订号、修改日期等)。
命令格式:
svn propset svn:keywords “Id” prosetfile
svn:keywords参数
Id: 这是一种综合的格式,如”$Id: ProductController.php 13308 2011-09-01 09:01:02Z wbq $”
LastChangedDate: 最后被修改的时间,这个属性也可以缩写为Date。
LastChangedBy: 最后修改该源代码文件的用户名,这个属性也可以被缩写为Author。
LastChangedRevision: 最后修订的版本号,这个属性也可以被缩写为Revision或者Rev。
HeadURL: 该源代码文件所位于的 Repository 上的绝对 URL 地址,这个属性也可以被缩写为URL。
下面是一个实例
1、config.php的原始文件;
/** * DF3C 前台公用文件 * ============================================== * 版权所有 2010-2011 http://www.df3c.com * ---------------------------------------------- * 这不是一个自由软件,未经授权,不允许任何个人或组织传播和使用。 * ============================================== * @date: 2011-10-7 * @author: wumh * @version: */ // database host $db_host = "localhost:3306"; // database name $db_name = "shop"; // database username $db_user = "root"; // database password $db_pass = "";
2、设置keywords属性
svn propset svn:keywords “Id” config.php
注:如果使用的是TortoiseSVN这样的图形界面工具,为“右击文件->properties->new->svn:keywords”,然后输入参数Id或LastChangedDate、Author等,设置多个关键字用换行分开。
Subversion只会对明确指定关键字进行更新,未指定的关键字不会更新到文件中。
3、在config.php中加入关键字
/** * DF3C 前台公用文件 * ============================================== * 版权所有 2010-2011 http://www.df3c.com * ---------------------------------------------- * 这不是一个自由软件,未经授权,不允许任何个人或组织传播和使用。 * ============================================== * @date: 2011-10-7 * @author: wumh * @version: $Id$ */ // database host $db_host = "localhost:3306"; // database name $db_name = "shop"; // database username $db_user = "root"; // database password $db_pass = "";
在@version: 后面增加“$Id$”,也可以是“$LastChangedDate$”、“$Author$”等。
4、提交更新
在subversion中提交修改后,就会变为类似上面你所看到的内容。
/** * DF3C 前台公用文件 * ============================================== * 版权所有 2010-2011 http://www.df3c.com * ---------------------------------------------- * 这不是一个自由软件,未经授权,不允许任何个人或组织传播和使用。 * ============================================== * @date: 2011-10-7 * @author: wumh * @version: $Id: index.php 21 2011-10-07 03:53:20Z wumh $ */ // database host $db_host = "localhost:3306"; // database name $db_name = "shop"; // database username $db_user = "root"; // database password $db_pass = "";
相关应用
在web服务器中,为了提高性能,大多时候都会启用缓存策略。而缓存的机制多是围绕url实现,这样常常会导致不清空缓存不能换取最新文件的情况。 为解决这种问题,我们可以在url后面增加一个$Rev$的参数。如:../style.css?v=$Rev$ 或 ../base.js?v=$Rev$
转自 http://victorwmh.iteye.com/blog/907012
绘制图象为什么会闪烁与双缓冲的作用
1、显示的图形为什么会闪烁?
我们的绘图过程大多放在OnDraw或者OnPaint函数中,OnDraw在进行屏幕显示时是由OnPaint进行调用的。当窗口由于任何原因需 要重绘时,总是先用背景色将显示区清除,然后才调用OnPaint,而背景色往往与绘图内容反差很大,这样在短时间内背景色与显示图形的交替出现,使得显 示窗口看起来在闪。如果将背景刷设置成NULL,这样无论怎样重绘图形都不会闪了。当然,这样做会使得窗口的显示乱成一团,因为重绘时没有背景色对原来绘 制的图形进行清除,而又叠加上了新的图形。有的人会说,闪烁是因为绘图的速度太慢或者显示的图形太复杂造成的,其实这样说并不对,绘图的显示速度对闪烁的 影响不是根本性的。例如在OnDraw(CDC *pDC)中这样写:
pDC->MoveTo(0,0);
pDC->LineTo(100,100);
这个绘图过程应该是非常简单、非常快了吧,但是拉动窗口变化时还是会看见闪烁。其实从道理上讲,画图的过程越复杂越慢闪烁应该越少,因为绘图用的时 间与用背景清除屏幕所花的时间的比例越大人对闪烁的感觉会越不明显。比如:清楚屏幕时间为1s绘图时间也是为1s,这样在10s内的连续重画中就要闪烁5 次;如果清楚屏幕时间为1s不变,而绘图时间为9s,这样10s内的连续重画只会闪烁一次。这个也可以试验,在OnDraw(CDC *pDC)中这样写:
for(int i=0;i<100000;i++)
{
pDC->MoveTo(0,i);
pDC->LineTo(1000,i);
}
呵呵,程序有点变态,但是能说明问题。
说到这里可能又有人要说了,为什么一个简单图形看起来没有复杂图形那么闪呢?这是因为复杂图形占的面积大,重画时造成的反差比较大,所以感觉上要闪 得厉害一些,但是闪烁频率要低。那为什么动画的重画频率高,而看起来却不闪?这里,我就要再次强调了,闪烁是什么?闪烁就是反差,反差越大,闪烁越厉害。 因为动画的连续两个帧之间的差异很小所以看起来不闪。如果不信,可以在动画的每一帧中间加一张纯白的帧,不闪才怪呢。
2、如何避免闪烁
在知道图形显示闪烁的原因之后,对症下药就好办了。首先当然是去掉MFC提供的背景绘制过程了。实现的方法很多,
* 可以在窗口形成时给窗口的注册类的背景刷付NULL
* 也可以在形成以后修改背景
static CBrush brush(RGB(255,0,0));
SetClassLong(this->m_hWnd,GCL_HBRBACKGROUND,(LONG)(HBRUSH)brush);
* 要简单也可以重载OnEraseBkgnd(CDC* pDC)直接返回TRUE
这样背景没有了,结果图形显示的确不闪了,但是显示也象前面所说的一样,变得一团乱。怎么办?这就要用到双缓存的方法了。双缓冲就是除了在屏幕上有图形进行显示以外,在内存中也有图形在绘制。我们可以把要显示的图形先在内存中绘制好,然后再一次性的将内存中的图形按照一个点一个点地覆盖到屏幕上去(这个过程非常快,因为是非常规整的内存拷贝)。这样在内存中绘图时,随便用什么反差大的背景色进行清除都不会闪,因为看不见。当贴到屏幕上时,因为内存中最终的图形与屏幕显示图形差别很小(如果没有运动,当然就没有差别),这样看起来就不会闪。
flash版本更新导致shopex后台上传图片无效的问题
4.8.4~4.8.5版本好像都有这个问题,下面是官方bbs上找到的补丁包,通过ftp上传覆盖就行了
文件清单
文件名 文件路径: 说明
component.js shopadmin\js\package\component.js JS文件-替换
uploader.swf shopadmin\images\uploader.swf flash文件-新增
frame.html core\admin\view\product\detail\frame.html 商品图片上传-替换
list.html core\admin\view\system\template\list.html 模板上传-替换
uploader.html core\admin\view\system\tools\ uploader.html 上传按钮-替换
解决bluehost主机同域邮件无法发送的问题
bluehost主机,用php自带的mail函数给同域的邮件发送邮件的时候会有个问题,比如我的域名是anfirst.com,如果给info@anfirst.com就会失败,原因很简单,因为bluehost本身自带了smtp服务,如果给同域名的邮箱发送邮件,bluehost就错误的以为这个邮箱的服务器就是localhost,即使这个域名的真实mx记录不是这台服务器。
解决办法也很简单,我们要修改bluehost的默认配置。
在cpanel配置面板,从mail下面的mx entry下面进去,从上面的下拉框里选择相应域名,再下面的 MX (Mail Exchanger) 项,点击下面的小小的more链接
在出现的单选列表中,选择 Remote Mail Exchanger 点击change按钮保存。

到此为止,这个问题就已经解决了
Editplus支持的正则表达式详解
- \t Tab character.tab符号
- \n New line.新的一行(换行符)
- . Matches any character.任何字符
- | Either expression on its left and right side matches the target string.For example, “a|b” matches “a” and “b”.|符号两边的都匹配
- [] Any of the enclosed characters may match the target character.For example, “[ab]” matches “a” and “b”. “[0-9]” matches any digit.用[]括起来的都匹配
- [^] None of the enclosed characters may match the target character.For example, “[^ab]” matches all character EXCEPT “a” and “b”.“[^0-9]” matches any non-digit character.用[]括起来的都“不匹配”
- * Character to the left of asterisk in the expression should match 0 or more times.For example “be*” matches “b”, “be” and “bee”.“*”号左边的那个字符匹配0次或者更多次
- + Character to the left of plus sign in the expression should match 1 or more times.For example “be+” matches “be” and “bee” but not “b”.“*”号左边的那个字符匹配1次或者更多次
- ? Character to the left of question mark in the expression should match 0 or 1 time.For example “be?” matches “b” and “be” but not “bee”.“*”号左边的那个字符匹配0次或者1次
- ^ Expression to the right of ^ matches only when it is at the beginning of line.For example “^A” matches an “A” that is only at the beginning of line.只匹配以“^”号右边的字符为一行开头的字符。
- $ Expression to the left of $ matches only when it is at the end of line.For example “e$” matches an “e” that is only at the end of line.只匹配以“$”号左边的字符为一行结束的字符。
- () Affects evaluation order of expression and also used for tagged expression.标示表达式区域
- \ scape character. If you want to use character “\” itself, you should use “\\”.转义字符,如果你想匹配”\”。请使用”\\”
- \0你使用正则表达式找到的东西
原始文本如下面两行
abc aaaaa
123 abc 444
即上面的文本最终替换为:
abc efg
123 abc efg
① 在替换对话框,查找内容里输入“abc.*”
② 同时勾选“正则表达式”复选框,然后点击“全部替换”按钮
其中,符号的含义如下:
“.” =匹配任意字符
“*” =匹配0次或更多
希望把
asdadas123asdasdas456asdasdasd789asdasd
替换为:
asdadas[123]asdasdas[456]asdasdasd[789]asdasd
在查找内容里面输入“[0-9][0-9][0-9]”,不含引号
“替换为:”里面输入“[\0\1\2]”,不含引号
范围为你所操作的范围,然后选择替换即可。
上面重复使用了“[0-9]”,表示连续出现的三个数字
“\0”代表第一个“[0-9]”对应的原型,“\1”代表第二个“[0-9]”对应的原型,依此类推 “[”、“]”为单纯的字符,表示添加“[”或“]”,如果输入“其它\0\1\2其它”,则替换结果为:
如果将查找内容“[0-9][0-9][0-9]”改为“[0-9]*[0-9]”,对应1 或 123 或 12345 或 …
大家根据需要定制
因为这几个字符在行中也是出现的,所以肯定不能用简单的替换实现
比如
12345 1265345
2345
需要删除每行末尾的“345”
这个也算正则表达式的用法,其实仔细看正则表达式应该比较简单,不过既然有这个问题提出,说明对正则表达式还得有个认识过程,解决方法如下
解决:
在替换对话框中,启用“正则表达式”复选框
在查找内容里面输入“345$”
这里“$”表示从行尾匹配
a. 选择要操作的行
b. 编辑-格式-删除行注释
c. 在弹出对话框里面输入要清除的行首字符,确定
几百个网页中都有下面一段代码:
<SCRIPT LANGUAGE=”JavaScript1.1″>
<!–
htmlAdWH(’93163607′, ’728′, ’90′);
//–>
</SCRIPT>
我想把它们都去掉,可是找了很多search & replace的软件,都是只能对“一行”进行操作。
具体解决方法,在 Editplus 中使用正则表达式,由于“(”、“)”被用做预设表达式(或者可以称作子表达式)的标志,所以查找
“<SCRIPT LANGUAGE=”JavaScript1.1″>\n<!–\nhtmlAdWH(’93163607′, ’728′, ’90′.);\n//–>\n</SCRIPT>\n”
时会提示查找不到,所以也就无法进行替换了,这时可以把“(”、“)”使用任意字符标记替代,即半角句号:“.”。替换内容为
<SCRIPT LANGUAGE=”JavaScript1.1″>\n<!–\nhtmlAdWH.’93163607′, ’728′, ’90′.;\n//–>\n</SCRIPT>\n
在替换对话框启用“正则表达式”选项,这时就可以完成替换了
对( ) 这样的特殊符号,应该用\( \)来表示,这也是很标准的regexp语法,可以写为
<SCRIPT LANGUAGE=”JavaScript1.1″>\n<!–\nhtmlAdWH\(’93163607′, ’728′, ’90′\);\n//–>\n</SCRIPT>\n
【5】正则表达式应用——删除空行
启动EditPlus,打开待处理的文本类型文件。
①、选择“查找”菜单的“替换”命令,弹出文本替换对话框。选中“正则表达式”复选框,表明我们要在查找、替换中使用正则表达式。然后,选中“替换范围”中的“当前文件”,表明对当前文件操作。
②、单击“查找内容”组合框右侧的按钮,出现下拉菜单。
③、下面的操作添加正则表达式,该表达式代表待查找的空行。(技巧提示:空行仅包括空格符、制表符、回车符,且必须以这三个符号之一作为一行的开头,并且以回车符结尾,查找空行的关键是构造代表空行的正则表达式)。
直接在”查找”中输入正则表达式“^[ \t]*\n”,注意\t前有空格符。
(1)选择“从行首开始匹配”,“查找内容”组合框中出现字符“^”,表示待查找字符串必须出现在文本中一行的行首。
(2)选择“字符在范围中”,那么在“^”后会增加一对括号“[]”,当前插入点在括号中。括号在正则表达式中表示,文本中的字符匹配括号中任意一个字符即符合查找条件。
(3)按一下空格键,添加空格符。空格符是空行的一个组成成分。
(4)选择“制表符”,添加代表制表符的“\t”。
(5)移动光标,将当前插入点移到“]”之后,然后选择“匹配 0 次或更多”,该操作会添加星号字符“*”。星号表示,其前面的括号“[]”内的空格符或制表符,在一行中出现0个或多个。
(6)选择“换行符”,插入“\n”,表示回车符。
④、“替换为”组合框保持空,表示删除查找到的内容。单击“替换”按钮逐个行删除空行,或单击“全部替换”按钮删除全部空行(注意:EditPlus有时存在“全部替换”不能一次性完全删除空行的问题,可能是程序BUG,需要多按几次按钮)。
shopex中集成的站长统计功能简单分析
shopex中集成了一键开启站长统计功能,而无需去CNZZ注册,在phpcms,phpwind等中也都有类似的功能,下面是对这个功能的简单分析,以后也可以偷偷用在自己的网站中,呵呵。
<?php
//我们的域名,这里可以不唯一的
$domain = 'localhost';
//这个应该是CNZZ授权给shopex的加密密钥,如果错了就不能快捷申请账号
$encodestr = 'A34dfwfF';
//这个就是CNZZ授权给shopex的快捷申请账号的URL地址
$url = 'http://wss.cnzz.com/user/companion/shopex.php?domain='.$domain.'&key='.md5($domain.$encodestr);
//获取网页内容得到这样的一个字符串 80772914@3780692425
$res = file_get_contents($url);
//左边是CNZZ统计的站点id,右边是密码
$res = explode('@',$res);
//登录到CNZZ统计的URL,把下面的地址复制到地址栏就可以看到效果了
//http://wss.cnzz.com/user/companion/shopex_login.php?site_id=80772914&password=3780692425
//会自动跳转到 http://wss.cnzz.com/v1/main.php?siteid=80772914&s=main_stat
$login = 'http://wss.cnzz.com/user/companion/shopex_login.php?site_id='.$res[0].'&password='.$res[1];
header("Location:$login");
php pdo中bindParam() 和 bindValue()方法的区别
方法 bindParam() 和 bindValue() 非常相似。
唯一的区别就是前者使用一个PHP变量绑定参数,而后者使用一个值。
所以使用bindParam是第二个参数只能用变量名,而不能用变量值,而bindValue至可以使用具体值。
$stm = $pdo->prepare("select * from users where user = :user");
$user = "jack";
//正确
$stm->bindParam(":user",$user);
//错误
//$stm->bindParam(":user","jack");
//正确
$stm->bindValue(":user",$user);
//正确
$stm->bindValue(":user","jack");
另外在存储过程中,bindParam可以绑定为input/output变量,如下面:
$stm = $pdo->prepare("call func(:param1)");
$param1 = "abcd";
$stm->bindParam(":param1",$param1); //正确
$stm->execute();
存储过程执行过后的结果可以直接反应到变量上。
对于那些内存中的大数据块参数,处于性能的考虑,应优先使用前者。
php截取html字符串,并自动补全html代码
实际开发中会经常碰到,很多人直接先strip_tags过滤掉html标签,但是就只剩下纯文本了,可读性非常差,下面是一个函数
/**
* 截取HTML,并自动补全闭合
* @param $html
* @param $length
* @param $end
*/
function subHtml($html,$length) {
$result = '';
$tagStack = array();
$len = 0;
$contents = preg_split("~(<[^>]+?>)~si",$html, -1,PREG_SPLIT_NO_EMPTY| PREG_SPLIT_DELIM_CAPTURE);
foreach($contents as $tag)
{
if (trim($tag)=="") continue;
if(preg_match("~<([a-z0-9]+)[^/>]*?/>~si",$tag)){
$result .= $tag;
}else if(preg_match("~</([a-z0-9]+)[^/>]*?>~si",$tag,$match)){
if($tagStack[count($tagStack)-1] == $match[1]){
array_pop($tagStack);
$result .= $tag;
}
}else if(preg_match("~<([a-z0-9]+)[^/>]*?>~si",$tag,$match)){
array_push($tagStack,$match[1]);
$result .= $tag;
}else if(preg_match("~<!--.*?-->~si",$tag)){
$result .= $tag;
}else{
if($len + mstrlen($tag) < $length){
$result .= $tag;
$len += mstrlen($tag);
}else {
$str = msubstr($tag,0,$length-$len+1);
$result .= $str;
break;
}
}
}
while(!empty($tagStack)){
$result .= '</'.array_pop($tagStack).'>';
}
return $result;
}
/**
* 截取中文字符串
* @param $string 字符串
* @param $start 起始位
* @param $length 长度
* @param $charset 编码
* @param $dot 附加字串
*/
function msubstr($string, $start, $length,$dot='',$charset = 'UTF-8') {
$string = str_replace(array('&', '"', '<', '>',' '), array('&', '"', '<', '>',' '), $string);
if(strlen($string) <= $length) {
return $string;
}
if(strtolower($charset) == 'utf-8') {
$n = $tn = $noc = 0;
while($n < strlen($string)) {
$t = ord($string[$n]);
if($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
$tn = 1; $n++;
} elseif(194 <= $t && $t <= 223) {
$tn = 2; $n += 2;
} elseif(224 <= $t && $t <= 239) {
$tn = 3; $n += 3;
} elseif(240 <= $t && $t <= 247) {
$tn = 4; $n += 4;
} elseif(248 <= $t && $t <= 251) {
$tn = 5; $n += 5;
} elseif($t == 252 || $t == 253) {
$tn = 6; $n += 6;
} else {
$n++;
}
$noc++;
if($noc >= $length) {
break;
}
}
if($noc > $length) {
$n -= $tn;
}
$strcut = substr($string, 0, $n);
} else {
for($i = 0; $i < $length; $i++) {
$strcut .= ord($string[$i]) > 127 ? $string[$i].$string[++$i] : $string[$i];
}
}
return $strcut.$dot;
}
/**
* 取得字符串的长度,包括中英文。
*/
function mstrlen($str,$charset = 'UTF-8'){
if (function_exists('mb_substr')) {
$length=mb_strlen($str,$charset);
} elseif (function_exists('iconv_substr')) {
$length=iconv_strlen($str,$charset);
} else {
preg_match_all("/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/", $text, $ar);
$length=count($ar[0]);
}
return $length;
}
巧用金山快盘搭建多地可用的SVN”服务器”
这里说的SVN服务器,并不是一个真正的服务器,却具有svn服务器的功能。因为有些代码在家里和公司都需要维护,代码的同步变得有些麻烦,一开始用了google code,孰料google被狙,gogole account都登陆不上了,经过研究,发现了一个利用金山快盘搭建svn服务器的功能。
客户端用TortoiseSVN,其实TortoiseSVN不仅仅是个SVN客户端,还集成了一些svn服务器进行版本库管理的功能。在金山快盘里建立一个文件夹svn,在svn目录再建立一个空文件夹 project,在此文件夹上点右键,在弹出菜单中的TortoiseSvn下执行”在此创建版本库”命令。这样版本库就创建在了快盘上,以后版本库任意的改动,金山网盘都会帮我们自动同步到各台电脑上,当然前提是这些电脑都是开启了使用同一个账户的快盘。
版本库建好了,就相当于我们在每台有快盘的机器上都有个SVN服务器端,只是这里的版本库URL设置成版本库的位置 file:///X:/svn/project,这时就可以从TortoiseSVN里检出(checkout),提交(commit),和更新(update)了,这样我在公司修改了代码,提交以后,金山快盘会帮我把版本库文件同步到家里的电脑上,回到家里我只需要update一下,就可以看到在公司修改后的代码了。
顺便帮金山坐下广告,申请金山快盘的地址是:http://k.wps.cn/register/!
使用netbox把asp网站打包成本地运行的可执行程序
netbox相当于一个超级精简的IIS,按照其官方的说法是“NetBox 提供 Microsoft IIS 5.0 兼容的 Active Server Pages 模块,不用修改代码直接将已经存在的使用 ASP 开发的应用程序移植到 NetBox 平台上来”,程序下载 http://www.netbox.cn:88/download/index.htm
安装完成后,使用非常简单,下面是个小例子
建立一个文件夹 wwwroot,把asp网站的程序和数据库等文件放在这里,相当于是网站的根目录
与wwwroot同级目录建立一个main.box文本文件,内容如下
Dim httpd
Shell.Service.RunService “NBWeb”, “NetBox Web Server”, “NetBox Http Server Sample”
‘———————- Service Event ———————
Sub OnServiceStart()
Set httpd = NetBox.CreateObject(“NetBox.HttpServer”)If httpd.Create(“”, 8080) = 0 Then
Set host = httpd.AddHost(“”, “\wwwroot”)host.EnableScript = true
‘———————-默认首页文件定义
host.AddDefault “index.asp”
host.AddDefault “default.asp”
host.AddDefault “default.htm”httpd.Start
‘——–下面这里是定义运行exe文件后直接打开一个网页窗口,可以不要,直接在浏览器通过地址打开
Set htWin= CreateObject(“NetBox.HtmlWindow”)
htWin.ContextMenu=false
htWin.AllowClose=true
htWin.Width=723
htWin.Height=584
htWin.Title=”华康名家私8周年店庆抽奖系统”
htWin.scrollbar=false
htWin.Open “http://127.0.0.1:8080/”
htWin.ShowDialogelse
Shell.Quit 0
end if
End SubSub OnServiceStop()
httpd.Close
‘Shell.Quit 0
End SubSub OnServicePause()
httpd.Stop
End SubSub OnServiceResume()
httpd.Start
End Sub
再建立的main.box文件上右键,build,生成exe文件,运行之即可

近期评论