存档

‘全部文章’ 分类的存档

判断一个数是否是2的次方

2010年1月20日 1 条评论

经典的:
int IsPower(unsigned n)
{
if(n==0)
return 1;
while(n)
{
if(n%2==0)
{
n = n/2;
if(n==1)
return 1;
}
else return 0;
}
}
不必解释

超强的:
int IsPower(unsigned n)
{
return (n&&!(n&(n-1)));
}

解释:
如果一个数是2的次方,则转成2进制是首位为1,其余都为0,比如:
2(10) 4(100) 8(1000) 16(10000)……

如果一个数和全1的相与还是等于自己,则这个数就是2的次方

n&(n-1)计算的是全零的情况,故!(n&(n-1))是全1的情况

转自 http://hi.baidu.com/mzyse/blog/item/6b5f5517d5d9d30cc83d6da3.html

有关zen cart集成支付宝借口时提示ILLEGAL_SIGN 错误解决

2010年1月8日 6 条评论

这次开发zencart的过程中要用过国内大名鼎鼎的支付宝接口,从zencart.cn上下了jack的 zen cart 支付宝模块从后台安装一切ok,可是测试购物的时候遇到了 ILLEGAL_SIGN错误,找了很多答案,仔仔细细看了阿里提供的api文档,还是找不出问题所在。看来得靠自己了,对着firebug,一个个核对网站传输给支付宝的post数据,发现多了 btn_submit.x,btn_submit.x 这两个参数,我把form 的method改成get,从地址栏中去掉这两个参数再打开,成功转向支付宝收银台页面,看来果然是两个参数搞得鬼!
google了下submit.x,得到如下答案
根据图形提交按钮行为W3C的描述 :

When a pointing device is used to click on the image, the form is submitted and the click coordinates passed to the server.
当指针设备用于在图像上点击,表单提交和点击坐标传递给服务器。

The x value is measured in pixels from the left of the image, and the y value in pixels from the top of the image.
在x值的单位是像素从左边的形象,以像素为单位从图像的顶部y值。

The submitted data includes name.x=x-value and name.y=y-value where “name” is the value of the name attribute, and x-value and y-value are the x and y coordinate values, respectively.
提交的数据包括name.x = x值和name.y = y值在“名称”的名称属性值和x值和y值是x和y坐标值。

于是这还是W3C的标准,现在的问题就是如何避免浏览器“多此一举”了,很简单,在表单添加onsubmit=”this.submit();return false;”,即修改zencart的订单确认页面模板tpl_checkout_confirmation_default.php文件中的

echo zen_draw_form(‘checkout_confirmation’, $form_action_url, ‘post’, ‘id=”checkout_confirmation” onsubmit=”submitonce();”‘);

修改为

echo zen_draw_form(‘checkout_confirmation’, $form_action_url, ‘post’, ‘id=”checkout_confirmation” onsubmit=”this.submit();return false;”‘);

自己制作的umd电子书thinking in java中文版下载

2009年11月28日 1 条评论

先说下这本书确实很不错,先是因为朋友的推荐,下了电子版,立即被其中深入透彻的内容吸引了,然后从当当买了纸质的,这也是我买过的最贵的几本书之一了,后来为了方便在上下班路上用手机阅读,又自己根据电子版的pdf文件转成了txt格式的,无奈txt格式的没有目录结构,阅读查找起来实在是很不方便,于是又弄成了umd格式的,目录做到了每一章,呵呵,因为涉及到文件切割,编码问题,这个umd还是花了不少时间,当然好东西怎能一个人分享呢,下面是下载地址,喜欢的朋友可以留个脚印。
Think in java中文版

强大的php魔术,类方法的overload,cakephp中findby的实现

2009年11月19日 1 条评论

今天又摸了下cakephp,突然想研究一下cakephp中modle所提供的findbyfieldname..这样的方法,深入研究了一下,又发现了php的一个新技能!这确实是一个很有魔力的东西,简单代码如下

class OverLoadable{
//这个方法,当调用类中不存在的的方法时会调用这个方法,php自动把这个不存在的方法名和这个方法里的变量数组填充进这个方法并自动调用,于是我要findbyUsername时, 我就可以简单的通过正则提取出方法名中的Username这个字符串,然后传递给类中真正存在的方法findbyfield($field),这样就间接的实现了findbyUsername方法
于是这里,我就可以通过正则提出出方法名
function __call($method, $params){
if(preg_match(“/findby(?P.*)/i”,$method,$preg))
return $this->findbyfield($preg['field']);
}

function findbyfield($field)
{
echo $field;
}
//当读取类的成员变量不存在时,触发这个方法,以你要读取的变量名作为参数
function __get($name){
echo “Your val is $name,and is not exsit in this class!”;
}
//当写入类的成员变量不存在时,触发这个方法,以你要写入的变量名和值作为参数
function __set($name,$value){
echo ‘Your val is ‘.$name.’=>’.$value;
}
}

$oo = new OverLoadable();
$oo->findbyusername();
$oo->i = 5;
?>

php采集类

2009年10月29日 没有评论

一个自己写的php采集类,充分利用正则的强大字串处理能力,使用简单,功能也比较简单,能满足一般应用,功能也在不断完善中,使用过程:设置一个初始url,添加导航规则,添加采集字段和规则,保存输出即可

使用代码如下

$spider  = new spider();
$spider->addStartUrl(‘http://www.onlinedown.net/hits/week_{2,3}.htm’);
$spider->addLayer(0,’list’,’../soft/{*}.htm’);
$spider->addField(‘title’,'<title>{title}</title>’,array(‘华军软件园’,'安风信息网’));
$spider->run();
$spider->output();

上面采集的是华军软件的一周软件排行
源码如下

set_time_limit(0);
header("Content-type: text/html; charset=utf-8");
/**
* 采集程序类
* @author shooting
* @version 1.0.0
*/
class spider
{

/**
* 采集的终端页地址
*
* @var array
*/
var $pages = array();
/**
* 采集结果
*
* @var array
*/
var $result = array();
/**
* 第一层链接页面
*
* @var array
*/
var $startUrls = array();
/**
* 超时时间
*
* @var integer
*/
var $timeout;
/**
* 正在处理的文件内容
*
* @var string
*/
var $httpContent;
/**
* 正在处理的文件头
*
* @var array
*/
var $httpHead=array();
/**
* 自定义的head数组
*
* @var array
*/
var $putHead = array();
/**
* 采集字段与规则数组
*
* @var array
*/
var $field_arr = array();
/**
* 采集层次数
*
* @var interger
*/
var $deep;
/**
* 采集层次结构
*
* @var array
*/
var $layout_arr = array();
/**
* 采集限制条数
*
* @var integer
*/
var $limit = 0;

/**
* 程序运行时间
*
* @var float
*/
var $runtime = 0;

/**
* 被采集页面编码
*
* @var string
*/
var $charset = 'UTF-8';
/**
* 页面引用地址
*
* @var string
*/
var $httpreferer;

var $pagelimit = 0;

var $filepath = './';

function spider()
{
$this->timeout = 30;
}
/**
* 运行采集
*
* @return array
*/
function run()
{
$begintime = $this->microtime_float();
$cnt = 1;
foreach ($this->startUrls as $starturl){
/**
* 解析出起始地址中的页码区间
*/
if(preg_match(“~\{(\d+),(\d+)\}~”,$starturl,$pagenum)){
$pagebegin = intval($pagenum[1]);
$pageend = intval($pagenum[2]);
for(;$pagebegin<=$pageend;$pagebegin++){
$starturl = str_replace($pagenum[0],$pagebegin,$starturl);
$urllists = $this->getLists($this->layout_arr[0]['pattern'],$this->getContent($starturl));
foreach ($urllists as $url){
if(($this->limit > 0 && $cnt <= $this->limit)||$this->limit == 0)
{
$this->filterContent($this->getContent($url,$starturl));
$cnt++;
}
}
}
}else{
$urllists = $this->getLists($this->layout_arr[0]['pattern'],$this->getContent($starturl));
foreach ($urllists as $url){
if(($this->limit > 0 && $cnt <= $this->limit)||$this->limit == 0)
{
$this->filterContent($this->getContent($url,$starturl));
$cnt++;
}
}
}
}
$this->runtime = $this->microtime_float()-$begintime;
return $this->result;
}

/**
* 从文字段中根据规则提取出url列表
*
* @param string $pattern
* @param string $content
* @return Array
*/
function getLists($pattern=”,$content=”)
{
if(strpos($pattern,’{*}’) === false)return array($pattern);
$pattern = preg_quote($pattern);
$pattern = str_replace(‘\{\*\}’,'([^\'\">]*)’,$pattern);
$pattern = “~”.$pattern.”~is”;
preg_match_all($pattern,$content,$preg_rs);
return array_unique($preg_rs[0]);
}

/**
* 获取指定url的html内容包括头
*
* @param string $url
* @return string
*/
function getContent($url,$referer = ”)
{
$url = $this->urlRtoA($url,$referer);
preg_match(“/(http:\/\/)([^:\/]*):?(\d*)(\/?.*)/i”,$url,$preg_rs);
$host = $preg_rs[2];
$port = empty($preg_rs[3])?80:$preg_rs[3];
$innerUrl = $preg_rs[4];

$fsp = fsockopen($host,$port,$errno,$errstr,$this->timeout);
if(!$fsp)$this->log($errstr.’(‘.$errno.’)');
$output = “GET $url HTTP/1.0\r\nHost: $host\r\n”;
if(!isset($this->putHead['Accept']))$this->putHead['Accept']= “*/*”;
if(!isset($this->putHead['User-Agent']))$this->putHead['User-Agent']=’Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2)’;
if(!isset($this->putHead['Refer'])){
$this->putHead['Refer'] = ($referer == ”)?’http://’.$host:$referer;
}
foreach ($this->putHead as $headname => $headvalue){
$output .= trim($headname).’: ‘.trim($headvalue).”\r\n”;
}

$output .= “Connection: close\r\n\r\n”;
fwrite($fsp,$output);

$content = ”;
while (!feof($fsp)) {
$content .= fgets($fsp,256);
}
fclose($fsp);

$this->getHead($content);
$this->httpContent = $content;
if(strtoupper($this->charset) != ‘UTF-8′){
$content = iconv($this->charset,’utf-8′,$content);
}else if(!empty($this->httpHead['charset']) && $this->httpHead['charset']!=’UTF-8′)
{
$content = iconv($this->httpHead['charset'],’utf-8′,$content);
}
$this->httpreferer = $referer;
return $content;
}

/**
* 按照规则从内容提取所有字段
* @param Array
* @return Array
*/
function filterContent($content=”)
{
$rs = array();
foreach ($this->field_arr as $field => $fieldinfo){
$rs[$field] = $this->getPregField($fieldinfo,$content);
}
$this->result[] = $rs;
}
/**
* 相对路径转化为绝对路径
*
* @param string $relative
* @param string $referer
* @return string
*/
function urlRtoA($relative,$referer)
{
/**
* 去除#后面的部分
*/
$pos = strpos($relative,’#');
if($pos >0)$relative = substr($relative,0,$pos);
/**
* 检测路径如果是绝对地址直接返回
*/
if(preg_match(“~^(http|ftp)://~i”,$relative))
return $relative;
/**
* 解析引用地址,获得协议,主机等信息
*/
preg_match(“~((http|ftp)://([^/]*)(.*/))([^/#]*)~i”, $referer, $preg_rs);
$parentdir = $preg_rs[1];
$petrol = $preg_rs[2].’://’;
$host = $preg_rs[3];
/**
* 如果以/开头的情况
*/
if(preg_match(“~^/~i”,$relative))
return $petrol.$host.$relative;
return $parentdir.$relative;
}

/**
* 根据规则提取一个字段
*
* @param string $pattern
* @param string $content
* @return string
*/
function getPregField($fieldinfo,$content)
{
/**
* 规则为固定值的情况,直接返回固定值
*/
if(strpos($fieldinfo['pattern'],’{‘.$fieldinfo['field'].’}') === false)
return $fieldinfo['pattern'];
if($fieldinfo['isregular'] == ‘true’){
$pattern = $fieldinfo['pattern'];
$pattern = str_replace(‘{‘.$fieldinfo['field'].’}',’(?P<'.$fieldinfo['field'].'>.*?)’,$pattern);
}else{
$pattern = preg_quote($fieldinfo['pattern']);
$pattern = str_replace(‘\{‘.$fieldinfo['field'].’\}’,'(?P<'.$fieldinfo['field'].'>.*?)’,$pattern);
}
$pattern = “~”.$pattern.”~is”;
preg_match($pattern,$content,$preg_rs);
$fieldresult = $preg_rs[$fieldinfo['field']];
/**
* 去掉换行符
*/
$fieldresult = preg_replace(“~[\r\n]*~is”,”,$fieldresult);
/**
* 对采集到的结果根据规则再进行二次替换处理
*/
$replace_arr = $fieldinfo['replace'];
if(is_array($replace_arr)){
$replace_arr[0] = “~”.$replace_arr[0].”~s”;
$fieldresult = preg_replace($replace_arr[0],$replace_arr[1],$fieldresult);
}
/**
* 针对有下一页的字段递归采集
*/
if($this->pagelimit == 0){
if($fieldinfo['nextpage'] != ”){
$pattern = $fieldinfo['nextpage'];
$pattern = str_replace(‘{nextpage}’,'(?P[^\'\">]*?)’,$pattern);
$pattern = “~”.$pattern.”~is”;
if(preg_match($pattern,$content,$preg_rs) && $preg_rs['nextpage'] != ”){
$fieldresult .= $this->getPregField($fieldinfo,$this->getContent($preg_rs['nextpage'],$this->httpreferer));
}
}
}
if(!empty($fieldinfo['callback']))$fieldresult = $fieldinfo['callback']($fieldresult);
return $fieldresult;
}
/**
* 添加一个采集字段和规则
*
* @param string $field
* @param string $pattern
*/
function addField($field,$pattern,$replace_arr=”,$isregular=’false’,$nextpage = ”,$callback=”)
{
$rs = array(
‘field’ => $field,
‘pattern’ => $pattern,
‘replace’ => $replace_arr,
‘isregular’ => $isregular,
‘nextpage’ => $nextpage,
‘callback’=>$callback
);
$this->field_arr[$field] =$rs;
}
/**
* 输出
*
*/
function output()
{
echo “The result is:
“;
echo “runtime :$this->runtime S

";
		print_r($this->result);
		echo "

“;
}
/**
* 输出到XLS文件
*
* @param string $file
*/
function saveXls($file = ‘spider_result.xls’)
{
$fp = fopen($file,’w');
if($fp){
foreach ($this->result as $result)
{
$line = implode(“\t”,$result).”\n”;
fputs($fp,$line);
}
}
fclose($fp);
echo ‘The result has been saved to ‘.$file.’.
Cost time:’.$this->runtime;
}

function saveSql($table = ‘spider_result’,$file = ‘spider_result.sql’)
{
$fp = fopen($file,’w');
if($fp){

foreach($this->field_arr as $fieldinfo){
$sql_key .= ‘, `’.$fieldinfo['field'].’`';
}
$sql_key = substr($sql_key,1);
foreach ($this->result as $result)
{
$sql_value = array();
foreach ($result as $key => $value){
$sql_value[] = “‘”.$this->addslash($value).”‘”;
}
$line =”INSERT INTO `$table` ( $sql_key ) VALUES (“.join(‘, ‘,$sql_value).”);\r\n”;
fputs($fp,$line);
}
}
fclose($fp);
echo ‘The result has been saved to ‘.$file.’.
Cost time:’.$this->runtime;
}
/**
* 取得响应内容的头部信息
*
* @param string $content
* @return array
*/
function getHead($content)
{
$head = explode(“\r\n\r\n”,$content);
$head = $head[0];
// echo $head;
if(!preg_match(“~charset\=(.*)\r\n~i”,$head,$preg_rs))
preg_match(‘~charset=([^\"\']*)~i’,$content,$preg_rs);
$this->httpHead['charset'] = strtoupper(trim($preg_rs[1]));
// preg_match(“~charset\=(.*)~i”,$head,$preg_rs);
return $this->httpHead;
}
/**
* 设置采集页面的编码
* 在程序不能自动识别的情况下采集前要手动调用此函数
*
* @param string $charset
*/
function setCharset($charset){
$this->charset = strtoupper($charset);
}

/**
* 设置第一层链接页面地址
*
* @param array $url_arr
*/
function setStartUrls($url_arr)
{
$this->startUrls = $url_arr;
}

/**
* 增加一个第一层链接页面地址
*
* @param string $url
*/
function addStartUrl($url)
{
$this->startUrls[] = $url;
}
/**
* 添加一个采集层次
*
* @param integer $deep
* @param string $layout
* @param boolean $isSimple
* @param boolean $isPageBreak
* @param string $pattern
*/
function addLayer($deep,$layout,$pattern = ”,$isSimple = ‘false’,$isPageBreak = ‘false’)
{
$this->layout_arr[$deep] = array(
‘layout’=>$layout,
‘isSimple’=>$isSimple,
‘isPageBreak’=>$isPageBreak,
‘pattern’=>$pattern );

}

/**
* 自定义head
* @param string $namespace
* @param string $value
*/
function setHead($name,$value)
{
$this->putHead[$name] = $value;
}

/**
* 清除html代码
* @param string $content;
* @param string $cleartags
* @return string
*/
function clearHtml($content,$cleartags = ‘div’)
{
$cleartags_arr = explode(‘|’,$cleartags);

foreach ($cleartags_arr as $cleartag){
$pattern = ‘~<\/?'.$cleartag.'[^>]*>~is’;
$content = preg_replace($pattern,”,$content);
}
return $content;
}
/**
* 日志
*
*/
function log($str)
{
echo $str.”
\n”;
}
/**
* 获取采集运行时间
*
* @return float
*/
function getRuntime()
{
return $this->runtime;
}

function microtime_float()
{
list($usec, $sec) = explode(” “, microtime());
return ((float)$usec + (float)$sec);
}

function addslash($string)
{
return addslashes($string);
}
}

$spider = new spider();
$spider->addStartUrl(‘http://hi.baidu.com/shuntian/blog/index/{0,5}’);
$spider->setCharset(‘gb2312′);
$spider->addLayer(0,’list’,'/shuntian/blog/item/{*}.html’);
$spider->addField(‘title’,’‘,array(‘_顺者的天空-shooting's sky ‘,”));
$spider->addField(‘body’,’

{body}

‘);
$spider->addField(‘author’,'shooting’);
$spider->run();
$spider->saveSql();

php变量类型?内存指针?

2009年10月28日 没有评论

这个问题在C/C++语言中是个常见的问题,然而在php这种弱类型的语言中却并不被关注,个人觉得在php中探讨这个问题有点空中楼阁的感觉,因为php本身就是一种运行在Zend engine解释器基础上的一种语言,如果非要探讨这个问题,需要了解下php在zend引擎上的运行原理。
我们都知道C是强类型的语言,定义了的变量,在它的生命周期类就无法改变的,php这种弱类型的语言怎么能在C中完美运行呢?实际上php中的变量,在C中都是通过一个结构体来表示的,此结构体的定义是:

typedef struct _zval_struct {
zvalue_value value;
zend_uint refcount;
zend_uchar type;
zend_uchar is_ref;
} zval;

其中zvalue_value是真正保存数据的关键部分zvalue_value又是个联合体(union),结构如下

typedef union _zvalue_value {
long lval;
double dval;
struct {
char *val;
int len;
} str;
HashTable *ht;
zend_object_value obj;
} zvalue_value;

这个联合体中保存着一个弱类型的值常用的多种类型
zend engine根据 struct _zval_struct中的type来取union _zvalue_value中相应的单元,这就实现了php的多种类型间的自动转化。

总结,在php中探讨内存指针的问题没有意义,这应该是C/C++爱好者需要深入研究的问题!
深入内容参考 http://www.laruence.com/2008/08/22/412.html

我的wordpress图形验证码插件Wp-validcode

2009年10月25日 10 条评论

今天一天收到了65个垃圾评论,于是在前一个php验证码的基础上做出了自己的第一个wordpress插件,case见本站,下载地址在下面

wp-validcode

解压上传到wp-content/plugins目录,从后台安装即可!

已经调整为不区分大小写,验证码背景也进行了更换,更简单,但更具干扰性

mysql group by排序问题【转】

2009年10月18日 1 条评论

类如 有一个 帖子的回复表,posts( id , tid , subject , message ,  dateline ) ,

id为 自动增长字段, tid为该回复的主题帖子的id(外键关联),  subject 为回复标题, message 为回复内容, dateline 为回复时间,用UNIX 时间戳表示,

现在要求 选出 前十个来自不同主题的最新回复

SELECT * FROM posts GROUP BY  tid  LIMIT 10

这样一个sql语句选出来的并非你想要的 最新的回复,而是最早的回复,实际上是某篇主题的第一条回复记录!

也就是说 GROUP BY 语句没有排序,那么怎么才能让 GROUP 按照 dateline 倒序排列呢?加上 order by 子句?

看下面:

SELECT * FROM posts GROUP BY  tid  ORDER BY dateline DESC LIMIT 10

这条语句选出来的结果和上面的完全一样,不过把结果倒序排列了,而选择出来的每一条记录仍然是上面的记录,原因是 group by 会比 order by 先执行,这样也就没有办法将 group by 之前,也就是在分组之前进行排序了, 有网友会写出下面的sql 语句:

SELECT * FROM posts GROUP BY  tid DESC ORDER BY dateline DESC LIMIT 10

也就是说 在 GROUP BY 的字段 tid 后面加上递减顺序,这样不就可以取得分组时的最后回复了吗?这个语句执行结果会和上面的一模一样,这里加上 DESC 和ASC对执行结果没有任何影响!其实这是一个错误的语句,原因是GROUP BY 之前并没有排序功能,mysql 手册上面说,GROUP BY 时是按照某种顺序排序的,某种顺序到底是什么顺序?其实根本没有顺序,因为按照tid分组,其实也就是说,把tid相等的归纳到一个组,这样想的话,GROUP BY tid DESC 可以认为是在按照 tid 分组的时候,按照tid进行倒序排列,这不扯吗,既然是按照tid分组,当然是tid相等的归到一组,而这时候按照tid倒叙还是升序有个P用!

于是有网友发明下面的语句:

SELECT * FROM posts GROUP BY  tid , dateline DESC ORDER BY dateline DESC LIMIT 10

心想这样我就可以在分组前按照  dateline 倒序排列了,其实这个语句并没有起到按照tid分组的作用,原因还是上面的,在group by 字段后加 desc 还是 asc 是错误的写法,而这种写法 网友本意是想 按照 tid 分组,并且在分组的时候按照 dateline排倒序!而实际这句相当于下面的写法:(去掉 GROUP BY 字段后面的 DESC)

SELECT * FROM posts GROUP BY  tid , dateline ORDER BY dateline DESC LIMIT 10

也就是说,按照 tid 和 dateline 联合分组,只有在记录tid和dateline 同时相等的时候才归纳到一组,这显然不可能, 因为 dateline 时间线基本上是唯一的!

有人写出下面的语句:

SELECT *,max(dateline) as max_line FROM posts GROUP BY  tid ORDER BY dateline DESC LIMIT 10

这条语句的没错是选出了最大发布时间,但是你可以对比一下 dateline 和 max_dateline 并不相等!(可能有相当的情况,就是分组的目标记录只有一条的时候!)

为什么呢?原因很简单,这条语句相当于是 在group by 以后选出 本组的最大的 发布时间!对分组没有起到任何影响!因为SELECT子句是最后执行的!

后来更有网友发明了下面的写法!

SELECT *,max(dateline) as max_line FROM posts GROUP BY  tid HAVING dateline=max(dateline)

ORDER BY dateline DESC LIMIT 10

这条语句的预期结果和想象中的并不相同!因为你会发现,分组的结果中大量的记录没有了!为什么?因为 HAVING 是在分组的时候执行的,也就说:在分组的时候加上一个这样的条件:选择出来的 dateline 要和 本组最大的dateline 相等,执行的结果和下面的语句相同:

SELECT *,max(dateline) as max_line FROM posts GROUP BY  tid HAVING count(*)=1

ORDER BY dateline DESC LIMIT 10

看了这条sql语句是不是明白了呢?

dateline=max(dateline) 只有在分组中的记录只有一条的时候才成立,原因很明白吧!只有一条他才会和本组的最大发布时间相等阿,(默认dateline为不重复的值)

原因还是因为 group by 并没有排序功能,所有的这些排序功能只是错觉,所以你最终选出的 dateline 和max(dateline) 永远不可能相等,除非本组的记录只有一条!GROUP BY 在分组的时候,可能是一个一个来找的,发现有相等的tid,去掉,保留第一个发现的那一条记录,所以找出来的 记录永远只是按照默认索引顺序排列的!

那么说了这么多,到底有没有办法让 group by 执行前分组阿?有的 ,子查询阿!

最简单的 :

SELECT * FROM (SELECT * FROM posts ORDER BY dateline DESC) AS p GROUP BY  tid ORDER BY dateline DESC LIMIT 10

也有网友利用自连接实现的 ,这样的效率应该比上面的子查询效率高,不过,为了简单明了,就只用这样一种了,GROUP BY没有排序功能,可能是mysql弱智的地方,也许是我还没有发现.

preg_match 匹配中文出现错误bug的解决办法

2009年9月28日 没有评论

论坛上的一个网友提出的问题,在ascii编码的php文件中,定义的一个函数,简单描述如下:

function checkpost()

{

global $subject

$censoww=array(‘婊”);

preg_match(‘/’ . implode(‘|’, $censoww) . ‘/i’, $subject,$matches) ) { echo “非法内容”;}

这是一个简单的禁字检测程序,广泛应用在bbs等程序中.可是这里出现了个问题,但$subject=’存活’ 或者 ‘存货’等时,这个程序竟然也提示非法内容。首先我提倡在程序中统一使用utf-8编码,当然这个程序在utf-8编码下应该没有问题的,可是在ascii下,就会有一些奇怪的bug。这位网页的程序都是基于gbk的,不可能全部转码,只能打打补丁了,下面是简单的解决方案:

mb_internal_encoding(‘gbk’);//指定网络编码为gbk,这同时也作为正则匹配的编码

function checkpost()

{

global $subject

$censoww=array(‘婊”);

//这里使用mb_eregi 代替preg_match,mb_eregi本身支持多字节的正则匹配

if(mb_eregi( implode(‘|’, $censoww) , $subject,$matches) ) { echo “非法内容”;}

顺便翻译了下手册中关于这个函数的简单说明

mb_eregi() executes the regular expression match with multibyte support, and returns 1 if matches are found. This function ignore case. If the optional third parameter was specified, the function returns the byte length of matched part, and the array regs will contain the substring of matched string.
mb_eregi(),支持忽略大小写的多字节正则匹配,如果匹配成功,返回1,如果指定第三个可选参数,函数就返回匹配部分字节数,同时把所有匹配到的子串放在第三个参数指定的数组变量中

div+css 图片垂直居中解决办法

2009年9月27日 没有评论

一个简单的问题实现在div+css中实现起来可没有那么轻松,参考网上找到的一些资料,找到了一个相对比较简单,而且效果还不错的方案,如下:

html结构很简单如下

<div class=”img_wrap”><img src =”http://www.baidu.com/img/baidu_logo.gif” /></div>

css样式

.img_wrap{/*非IE的主流浏览器识别的垂直居中的方法*/
display: table-cell;
vertical-align:middle;
text-align:center;
*display: block;
*font-size: 131px;/*约为高度的0.873,150*0.873 约为131*/
width:150px;
height:150px;
border: 1px solid #ccc;}
.img_wrap img{vertical-align:middle;}