对uchome2.0 的function_common.php的研究

 

 

 

1、shtmlspecialchars

//取消HTML代码
function shtmlspecialchars($string) {
	if(is_array($string)) {
		foreach($string as $key => $val) {
			$string[$key] = shtmlspecialchars($val);
		}
	} else {
		$string = preg_replace('/&((#(\d{3,5}|x[a-fA-F0-9]{4})|[a-zA-Z][a-z0-9]{2,5});)/', '&\\1',
			str_replace(array('&', '"', '<', '>'), array('&amp;', '&quot;', '&lt;', '&gt;'), $string));
	}
	return $string;
}

 以上代码的意思是将html里的敏感字符比如,<>&"都转义成类似于&lt;这样的东西的。这个函数利用了一个递归的思想,是个人也能看懂。这里着重讲一下那个

$string = preg_replace('/&amp;((#(\d{3,5}|x[a-fA-F0-9]{4})|[a-zA-Z][a-z0-9]{2,5});)/', '&\\1',
			str_replace(array('&', '"', '<', '>'), array('&amp;', '&quot;', '&lt;', '&gt;'), $string));

 后面的str_replace是把 array('&', '"', '<', '>')和array('&amp;', '&quot;', '&lt;', '&gt;')进行相对应的匹配替代。但是如果仅仅这样做是有问题的,比如我之前有一个&#127;表示"---",那么替换后就变成&amp;#127这个显然是不正确的,我们希望这种情况下保留原字符串。所以需要用'/&amp;((#(\d{3,5}|x[a-fA-F0-9]{4})|[a-zA-Z][a-z0-9]{2,5});)/'去匹配像&amp;#127这样的被替换过的字符串,将其还原成&#127的形式。后面的"\\1"会匹配#127。

  但是我有一个问题,为什么要先替换掉"&"呢?

 

 

2、saddslashes

 

//SQL ADDSLASHES
function saddslashes($string) {
    if(is_array($string)) {
        foreach($string as $key => $val) {
            $string[$key] = saddslashes($val);
        }
    } else {
        $string = addslashes($string);
    }
    return $string;
}
 

 

这里其实是为了sql安全考虑,防止sql注入。会把引号和双引号都转义成\"和\'的形式,这里还会转义其他字符,我就不多讲了。

 

 

 

3、ssetcookie

//cookie设置
function ssetcookie($var, $value, $life=0) {
    global $_SGLOBAL, $_SC, $_SERVER;
    setcookie($_SC['cookiepre'].$var, $value, $life?($_SGLOBAL['timestamp']+$life):0, $_SC['cookiepath'], $_SC['cookiedomain'], $_SERVER['SERVER_PORT']==443?1:0);
}
 

这里%_SC['cookiepre']默认是uchome_,这个前缀表示这个cookie是和uchome相关的。那个life其实是一个unix时间戳,由于$_SGLOBAL['timestamp']是表示这段程序执行的时间,所以加上一个$life就表示过期的日子,这里是按照秒记的;如果是0的话,cookie的默认日期是当前浏览器,关闭就清除了。$_SC['cookiepath']是指有效的cookie的路径,如果你是设的“/”的话,然后又是localhost访问的,你会发现在你任何用localhost访问的网页都有这个cookie,最好还是设成你的项目路径如"/play",这里表示的是目录,其对其子目录也一样有效。后面的$_SC['cookiedomain']表示有效域名,这里如果你设成是www.example.com就表示只在www.example.com有效,如果你设成是.example.com就表示在子域名都有效。

 

 

4、dbconnect()

//数据库连接
function dbconnect() {
	global $_SGLOBAL, $_SC;

	include_once(S_ROOT.'./source/class_mysql.php');

	if(empty($_SGLOBAL['db'])) {
		$_SGLOBAL['db'] = new dbstuff;
		$_SGLOBAL['db']->charset = $_SC['dbcharset'];
		$_SGLOBAL['db']->connect($_SC['dbhost'], $_SC['dbuser'], $_SC['dbpw'], $_SC['dbname'], $_SC['pconnect']);
	}
}
 

这里面的那些变量其实都是在uchome里面的config.php配置的,每一次访问页面执行common.php的时候都会执行这个函数,以后每次执行数据库调用只要用$_SGLOBAL['db']就可以,这是一个封装数据库操作的类,有很多有用的方法。

其中的pcconnect(persistent connect)其实就是是否是否用数据连接池的意思(默认为0,也就是不用连接池),connect函数其有一段

if($pconnect) {
			if(!$this->link = @mysql_pconnect($dbhost, $dbuser, $dbpw)) {
				$halt && $this->halt('Can not connect to MySQL server');
			}
		} else {
			if(!$this->link = @mysql_connect($dbhost, $dbuser, $dbpw, 1)) {
				$halt && $this->halt('Can not connect to MySQL server');
			}
		}

 默认的话会执行第else的那个子句,这里的那个1就是new_link的意思。也就是当用相同的参数连接数据库的时候总是会新建一个连接。而上面的那个mysql_pconnect应该就是利用连接池里的资源,对应$pconnect为1。

 

5、showmessage

function showmessage($msgkey, $url_forward='', $second=1, $values=array()) {
	global $_SGLOBAL, $_SC, $_SCONFIG, $_TPL, $space, $_SN;
 obclean();
 //去掉广告
	$_SGLOBAL['ad'] = array();
	//语言
	include_once(S_ROOT.'./language/lang_showmessage.php');
	if(isset($_SGLOBAL['msglang'][$msgkey])) {
		$message = lang_replace($_SGLOBAL['msglang'][$msgkey], $values);
	} else {
		$message = $msgkey;
	}
	//手机
	if($_SGLOBAL['mobile']) {
		include template('showmessage');
		exit();
	}
	//显示
	if(empty($_SGLOBAL['inajax']) && $url_forward && empty($second)) {
		header("HTTP/1.1 301 Moved Permanently");
		header("Location: $url_forward");
	} else {
		if($_SGLOBAL['inajax']) {
			if($url_forward) {
				$message = "<a href=\"$url_forward\">$message</a><ajaxok>";
			}
			//$message = "<h1>".$_SGLOBAL['msglang']['box_title']."</h1><a href=\"javascript:;\" οnclick=\"hideMenu();\" class=\"float_del\">X</a><div class=\"popupmenu_inner\">$message</div>";
			echo $message;
			ob_out();
		} else {
			if($url_forward) {
				$message = "<a href=\"$url_forward\">$message</a><script>setTimeout(\"window.location.href ='$url_forward';\", ".($second*1000).");</script>";
			}
			include template('showmessage');
		}
	}
	exit();
}
 

 

obclean()就是将之前的曾有过的输出echo print全部都清楚掉,因为这里肯定是页面要跳转了,所以之前的逻辑都不用考虑了,只需要重定向就行了。

showmessage.php里可以看到,有一些如

'no_privilege_friendnum' => '您需要添加 \\1 个好友之后,才能进行本操作,<a href="cp.php?ac=friend&op=find">点这里添加好友</a>',
 'no_privilege_email' => '您需要验证激活自己的邮箱后才能进行本操作,<a href="cp.php?ac=password">点这里激活邮箱</a>',
 

这里其实有一个本地化的思想,我可以写几种的showmessage.php,前面的键保留不变,因为那是逻辑部分,后面我可以写成法语或是马来西亚语,我只要挂在不同的地方用不同的php文件就可以了。

这里的

if(isset($_SGLOBAL['msglang'][$msgkey])) {

		$message = lang_replace($_SGLOBAL['msglang'][$msgkey], $values);

	} else {

		$message = $msgkey;

	}

 

比如我调用了showmessage("no_prililege_friendnum",'club.php',2,array(8))

首先会查看是否有no_prililege_friendnum这样的key,发现有,再调用

lang_replace($_SGLOBAL['msglang'][$msgkey], $values)

"您需要添加 \\1 个好友之后,才能进行本操...."里的\\1变成我们传进去的8,这里用到了lang_replace这个函数具体是

//语言替换
function lang_replace



($text, $vars) {
	if($vars) {
		foreach ($vars as $k => $v) {
			$rk = $k + 1;
			$text = str_replace('\\'.$rk, $v, $text);
		}
	}
	return $text;
}
 

 

如果是手机访问这个页面直接返回那个showmesage的html,不会跳转。如果是正常的网页行为(非ajax请求)且用户设定$second为0,则直接301跳转。如果是ajax模式,且用户指定了跳转的url就返回

"<a href=\"$url_forward\">$message</a><ajaxok>"

没有指定url就返回那个本地化的信息message。

最后一个判断肯定是当url指定了并且second不为0的情况,这个也是最一般的情况,会先渲染出showmessage这个页面然后再设定时间跳转。

 

6、formhash

      通过这个函数来探讨表单验证,以login举例

//产生form防伪码
function formhash() {
	global $_SGLOBAL, $_SCONFIG;
	if(empty($_SGLOBAL['formhash'])) {
		$hashadd = defined('IN_ADMINCP') ? 'Only For UCenter Home AdminCP' : '';
		$_SGLOBAL['formhash'] = substr(md5(substr($_SGLOBAL['timestamp'], 0, -7).'|'.$_SGLOBAL['supe_uid'].'|'.md5($_SCONFIG['sitekey']).'|'.$hashadd), 8, 8);
	}
	return $_SGLOBAL['formhash'];
}

 这里的formhash我本以为应该是每一次请求的时候都不一样的,因为这里涉及到一个$_SGLOBAL['timestamp']当前时间的。但是我做实验的时候每一次都是一样的,为什么呢,因为这里$_SGLOBAL['timestamp']是时间戳,这里截取的是0到-7,也就是只要是在10的7次方秒内都可以算出来是一样的,当然我这里不够严谨,我的意思是formhash在相当长的一段时间内是不变的(如果是相同的supeid的话),为什么呢?为什么要这样做呢?

 

然后在html表单上总有一个隐形input,里面填的就是formhash,还有一个submit input填入了submit的类型

<input type="hidden" name="formhash" value="<!--{eval echo formhash();}-->" /></form>
<input


 type


="submit" 


id


="loginsubmit" 


name


="loginsubmit" 


value


="登录" 


class


="submit" 


/





>

 所以当我们用submitcheck("loginsubmit")时会是这样,

 

function submitcheck($var) {

	if(!empty($_POST[$var]) && $_SERVER['REQUEST_METHOD'] == 'POST') {

		if((empty($_SERVER['HTTP_REFERER']) || preg_replace("/https?:\/\/([^\:\/]+).*/i", "\\1", $_SERVER['HTTP_REFERER']) == preg_replace("/([^\:]+).*/", "\\1", $_SERVER['HTTP_HOST'])) && $_POST['formhash'] == formhash()) {

			return true;

		} else {

			showmessage('submit_invalid');

		}

	} else {

		return false;

	}

}
 

 

首先判断提交的类型是否是预期的,也就是loginsubmit,并且判断是否为post提交,这里有点莫名其妙,你都从$_POST里拿数据了,难道还不是post?然后有一个比较复杂的if语句,就是判断当前的域名和用户填写表单时所在的页面的url是否是同一个域名,在我本机上,就是localhost,再判断那个formhash等不等于当前。天啊!太麻烦了!为什么要这么做的呢?

 

 

7、updatetable

//更新数据

function updatetable($tablename, $setsqlarr, $wheresqlarr, $silent=0) {

	global $_SGLOBAL;



	$setsql = $comma = '';

	foreach ($setsqlarr as $set_key => $set_value) {//fix

		$setsql .= $comma.'`'.$set_key.'`'.'=\''.$set_value.'\'';

		$comma = ', ';

	}

	$where = $comma = '';

	if(empty($wheresqlarr)) {

		$where = '1';

	} elseif(is_array($wheresqlarr)) {

		foreach ($wheresqlarr as $key => $value) {

			$where .= $comma.'`'.$key.'`'.'=\''.$value.'\'';

			$comma = ' AND ';

		}

	} else {

		$where = $wheresqlarr;

	}

	$_SGLOBAL['db']->query('UPDATE '.tname($tablename).' SET '.$setsql.' WHERE '.$where, $silent?'SILENT':'');

}
 

 

除了这个updatetable其实还有一个iinserttable,我这里就只放一个updatetable。这里其实有点类似于DAO。把所有的CRUD都封装为一个函数,任何实体的CRUD都只要调用这个函数,因为操作都是差不多的。注意这里 $comma的妙用。

还有这里的query里的参数soelnt,这里如果设置成了silent则在mysql出错的俄时候不会在页面上显示MySQL Query Error等等的错误而是直接把那个错误忽略了。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值