smarty循环foreach,section实例详解

php里面的数组或者对像都可以有for,foreach,while,list each来循环出来,smarty里面也有这套方法,要不然php的数组对像数据,smarty就不知道怎么把显示出来。习惯的php里面的for,foreach,while的用法,刚一开始的时候,smarty里面循环数组老是忘,好记性不如烂笔头,还是把它记下来才是最好的。下面定界变量符号,我就用默认的大括号了。
一,foreache,foreacheelse,/foreache方法
1,它是section 之外处理循环的另一种方案(根据不同需要选择不同的方案).用于处理简单数组(数组中的元素的类型一致),它的格式比 section 简单许多,缺点是只能处理简单数组.
2,foreach 必须和 /foreach 成对使用,且必须指定 from 和 item 属性.

3,foreach可以圈套不过name必须为一
4,from 待循环数组的名称,key数组下标,item当前处理元素的变量名称,name该循环的名称,用于访问该循环
5,foreachelse 语句在 from 后面的数组对像没有值的时候被执行.
二,section,sectionelse,/section方法
section 用于遍历数组中的数据. section 标签必须成对出现. 必须设置 name 和 loop 属性. 名称可以是包含字母、数字和下划线的任意组合. 可以嵌套但必须保证嵌套的 name 唯一. 变量 loop (通常是数组)决定循环执行的次数. 当需要在 section 循环内输出变量时,必须在变量后加上中括号包含着的 name 变量. sectionelse 当 loop 变量无值时被执行.
section里面可以带的参数如下
1,name单次循环的名称,必须有的选项
2,loop循环的变量名称,必须有的选项
3,start 循环开始的KEY值 ,默认是从第一个开始,
4,step设置循环的跳跃数,step=2将只遍历下标为0、2、4等的元素.
5,max循环的次数,默认为1,
6,show是不是显示该循环
从上面参数中我们可以看到,没有提到下标,我们经常会用到数组下标。但是smarty里面带的有.
下面的arrayname是section里面的单次循环名称
a,$smarty.section.arrayname.index 数组下标,根foreach 的key差不多
b,$smarty.section.arrayname.index_prev 上次循环的下标 根$smarty.section.arrayname.loop差不多
c,$smarty.section.arrayname.index_next 下次循环的下标
d,$smarty.section.arrayname.iteration 第几次循环了 根rownum一样
e,$smarty.section.arrayname.first 第一次循环
f,$smarty.section.arrayname.last 最后一次循环
g,$smarty.section.arrayname.show 循环是否显示
h,$smarty.section.arrayname.total 总共循环了多少次
section得到数组对像里面的值
{section name=arrayname loop=$array}
{$array[arrayname.index]} ,{$array[arrayname]}二者是等价的,由起可见,有了上面的a-h是多么的重要
三,应用举例
1,一维数组

array (  
   "0" => 'home',  
   '1' => 'who',  
   '2'=> 'tank',  
   '3'=> 'what'  
  );  
$this->tpl->assign("onearray", $this->onearray);  

a),foreach来读取

{foreach from=$onearray kkey=k item=value }  
 一维key={$k}  一维value={$value}
{foreachelse} nothing {/foreach}

显示的结果是
一维key=0 一维value=home
一维key=1 一维value=who
一维key=2 一维value=tank
一维key=3 一维value=what
b),section来读取

{section name=one loop=$onearray start=0 step=1}  
 index={$smarty.section.one.index},  
 index_prev={$smarty.section.one.index_prev},  
 index_next={$smarty.section.one.index_next},  
 first={$smarty.section.one.first},  
 last={$smarty.section.one.last},  
 iteration ={$smarty.section.one.iteration},  
 total={$smarty.section.one.total},  
 value={$onearray[one]}
{sectionelse} nothing {/section}

显示的结果是
index=0, index_prev=-1, index_next=1, first=1, last=, iteration =1, total=4, value=home
index=1, index_prev=0, index_next=2, first=, last=, iteration =2, total=4, value=who
index=2, index_prev=1, index_next=3, first=, last=, iteration =3, total=4, value=tank
index=3, index_prev=2, index_next=4, first=, last=1, iteration =4, total=4, value=what
2,二维数组

array (  
   "test" => 'home',  
   '2' => 'who',  
   array (  
    "上海",  
    "born" => "安徽",  
    "name" => "海底苍鹰"  
   ),  
   array (  
    "1583456",  
    "fax" => "12345678",  
    "cell" => "13256478414"  
   )  
  );  
$this->tpl->assign("twoarray", $this->twoarray);  

a),foreach

{foreach from=$twoarray kkey=k item=value }  
 {if is_array($value)}  
  {foreach from=$value key=tk item=tv }  
   二维tkey={$tk}  二维value={$tv}
{foreachelse} 二维数组为空 {/foreach} {else} 一维key={$k} 一维value={$value}
{/if} {foreachelse} nothing {/foreach}

显示结果如下:
一维key=test 一维value=home
一维key=2 一维value=who
二维tkey=0 二维value=上海
二维tkey=born 二维value=安徽
二维tkey=name 二维value=海底苍鹰
二维tkey=0 二维value=1583456
二维tkey=fax 二维value=12345678
二维tkey=cell 二维value=13256478414
b),section

{section loop=$twoarray name=two }  
 {if is_array($twoarray[two])}  
  {section loop=$twoarray[two] name=aaa }  
   二维tkey={$smarty.section.aaa.index}  二维value={$twoarray[two][aaa]}
{sectionelse} 二维数组为空 {/section} {else} 一维key={$smarty.section.two.index} 一维value={$twoarray[two]}
{/if} {sectionelse} nothing {/section}

显示结果如下:
一维key=0 一维value=
一维key=1 一维value=
一维key=2 一维value=who
二维tkey=0 二维value=上海
二维tkey=1 二维value=
二维tkey=2 二维value=
如果是一维数组,并且带有下标的话,并且不是按0,1,2这样的顺序的话就取不到东西。这个能不能理解成foreach存在的理由。不过一般从数据库取数据都是二维数组,并且外层都是以0开始的。看下面的这个例子

array (  
 array (  
  'name' => 'tank',  
  'sex' => '男',  
  'old' => '28'  
 ),  
 array (  
  'name' => 'joyce',  
  'sex' => '女',  
  'old' => '111'  
 )  
);  

section循环

{section loop=$twoarray name=two}  
 name={$twoarray[two].name},sex={$twoarray[two].sex},old={$twoarray[two].old}
{sectionelse} nothing {/section}

显示结果
name=tank,sex=男,old=28
name=joyce,sex=女,old=111
5

转载请注明
作者:海底苍鹰
地址:http://blog.51yip.com/smarty/903.html

PHP采集程序相关

采集程序最简单的思路就是:获取页面代码——分析代码——获取需要的部分——写入数据库。

当然,在获取页面代码之前我们首先要获得被采集页面的url,这里我们从百度新闻获取某关键词最新新闻列表。

function get_baidu_news_url($str){
    if(!$str) return;
    $str = gbk($str);

    //使用正则匹配出列表中的新闻URL
    $html = utf8(file_get_contents('http://news.baidu.com/ns?tn=newstitle&cl=2&rn=20&word=' . urlencode($str)));
    preg_match_all("/<a href=http:\/\/(.+?)  mon=(.+?)>(.+?)<\/a>/is",$html,$match);

    $urlarr = $match[1];
    if($urlarr){
        //URL前面补上http://
        array_walk($new_urlarr, create_function('&$v', '$v = "http://".$v ;'));
        cache_write($cachename, $new_urlarr, CACHE_PATH);
    }
    return $new_urlarr;
}

拿到新闻页面的URL之后,下一步就是采集页面上的新闻,当然这一步要针对各个网站定制不同的匹配规则,这里以新浪为例。新浪新闻以“<!– 正文内容 begin –>”开始,“<!– 正文内容 end –>”结束,所以匹配正文的正则为

preg_match_all("/<!-- 正文内容 begin -->([\s|\S]*?)<!-- 正文内容 end -->/is",$html,$match);

同理,匹配标题的正则为

preg_match_all("/<h1 id=\"artibodyTitle\"(.*?)>(.+?)<\/h1>/is",$html,$title_match);

函数完整代码:

function news_content_sina($url){
    if(!$url) return;
    $html = utf8(file_get_contents($url));
    preg_match_all("/<!-- 正文内容 begin -->([\s|\S]*?)<!-- 正文内容 end -->/is",$html,$match);
 preg_match_all("/<h1 id=\"artibodyTitle\"(.*?)>(.+?)<\/h1>/is",$html,$title_match);

    $title = $title_match[2][0];
    $content = news_content_format($match[1][0]);
    if($title && $content) return compact('url','title','content');
}

上面方法中用到了 news_content_format(),这个方法是用来格式化采集到的正文,去掉js、css、iframe、注释以及站内链接,下面代码中可以看到,我们去除了站内链接但保留了其他的<a>标签链接,这样就可以避免某些重要外链丢失影响新闻完整性,比如某考试报名地址链接。

function news_content_format($content){
    $search = array ("'<script[^>]*?>.*?</script>'si",   // 去掉 javascript
                    "'<style[^>]*?>.*?</style>'si",   // 去掉 css
                    "'<iframe[^>]*?>.*?</iframe>'si",   // 去掉 iframe
                    "'<!--[/!]*?[^<>]*?>'si",           // 去掉 注释 标记
     "'<a(.*?) href=(.*?)(sina.com|weibo.com)(.*?)>(.*?)<\/a>'si",  // 去掉 内部 链接
    );
    $replace = array ("","","","","","\${5}"); 
    $content = preg_replace($search, $replace, $content);
 $content = strip_tags($content, '<p> <br> <img> <table> <tr> <td> <strong> <a>');
 return $content;
}

到这里,采集的功能基本上就完成了,但是还有一点要注意,就是新闻中的图片如果也需要采集到本地的话,就要用到下面这个方法。

function getimage($body){
 global $img_dir,$img_webhost;//本站图片目录、主机

 if(!empty($body)){  
  $body = stripslashes($body);
  $img_array = array();
        //匹配出采集内容中的图片地址
  preg_match_all("/(src|SRC)=[\"|'|]{0,}(http:\/\/(.*)\.(gif|jpg|jpeg|bmp|png))/isU",$body,$img_array);
  $img_array = array_unique($img_array[2]);
  set_time_limit(0);
        //定义图片名,创建目录
  $imgPath = $img_dir."/".strftime("%Y%m%d",time());
  $imgUrl = "http://".$img_webhost."/".$imgPath;
  $milliSecond = strftime("%H%M%S",time());
  if(!is_dir($imgPath)) @mkdir($imgPath,0777);
  foreach($img_array as $key =>$value)
  {
   $value = trim($value);
            //抓取图片并保存
   $get_file = @file_get_contents($value);
   $rndFileName = $imgPath."/".$milliSecond.$key.".".substr($value,-3,3);
   $fileurl = $imgUrl."/".$milliSecond.$key.".".substr($value,-3,3);
   if($get_file)
   {
    $fp = @fopen($rndFileName,"w");
    @fwrite($fp,$get_file);
    @fclose($fp);
   }
   $body = ereg_replace($value,$fileurl,$body);
  }
  return $body;
 }

写入数据库等常规的操作在这里就不再赘述。

IE里Iframe的Cookie问题

引用地址:http://www.cnblogs.com/cuihongyu3503319/archive/2009/05/12/1455063.html

当利用IFRAME时,记得要在相应的动态页的页头添加一下P3P的信息,否则IE会自觉的把IFRAME框里的COOKIE给阻止掉,产生问题.本身不保存自然就取不到了.这个其实是FRAMESET和COOKIE的问题,用FRAME或者IFRAME都会遇到.

只需要设置 P3P HTTP Header,在隐含 iframe 里面跨域设置 cookie 就可以成功。他们所用的内容是:

P3P: CP=’CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR’

ASP直接在头部加了头部申明,测试有效。
<%Response.AddHeader “P3P”, “CP=CAO PSA OUR”%>

php的话,应该是如下写法:
header(‘P3P: CP=CAO PSA OUR’);   //IE8
header(‘P3P:CP=”IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT”‘);  //IE7

ASP.NET的话
通过在代码上加Response.AddHeader(“P3P”, “CP=CAO PSA OUR”)或者在Window服务中将ASP.NET State Service 启动。

JSP:
response.setHeader(“P3P”,”CP=CAO PSA OUR”)

使用Google账户登陆(Oauth版)

首先要申请CONSUMER_KEY和CONSUMER_SECRET,申请地址:https://www.google.com/accounts/ManageDomains

OAuth验证第一步:Get a Request Token.
这个Request Token是请求一个令牌,来允许程序接入google的服务。具体做法是发送一个HTTP GET请求到https://www.google.com/accounts/OAuthGetRequestToken,并且在HTTP头里有一个Authorization字段,字段里的内容是OAuth开头,加一个空格,然后是每个参数join一个“,”和空格。此外google的OAuth还有一个SCOPE参数,这个不是标准OAuth里的。
最后注意端口是443,不然会收到一个302;如果程序有问题会收到一个400。如果是200,则在返回的HTTP BODY里取得$oauth_token,$oauth_token_secret保存好这两个值,下两步要用到。

第二步是用户操作部分,需要用户授权应用访问GOOGLE相关服务。
也就是redirect到 www.google.com/accounts/OAuthAuthorizeToken?oauth_token=刚才的KEY,获取用户联系人列表的scope是https://www.google.com/m8/feeds/,用户允许Access后就会跳转回刚才的页面,并且在URL参数里多了一个参数。

第三步是凭刚才URL里验证的参数发送一个GET请求到https://www.google.com/accounts/OAuthGetAccessToken,获取接入GOOGLE服务的权限,HEADER里仍旧要包含Authorization字段。得到KEY和SECRET后替换刚才一开始的KEY和SECRET,发送GET请求到 获取用户联系人的scope(https://www.google.com/m8/feeds/contacts/default/thin),max-results参数代表获取联系人的个数,返回的XML包含<id>为邮箱,<title>里面含有用户名,其中第一条记录就是用户本人的信息。

详细的技术文档在这里 http://code.google.com/apis/accounts/docs/OAuth_ref.html

 

参考地址:
http://dev.meettea.com/show-53-1.html
http://code.google.com/apis/accounts/docs/OAuth_ref.html
http://code.google.com/apis/gdata/faq.html#AuthScopes
http://adaishu.blog.163.com/blog/static/17583128620114974952393/

google帳戶登錄oauth版示例代碼

 

让JavaScript和PHP通用值为中文的cookie

引用地址:http://vseb.blog.sohu.com/67136922.html

这是一个哪里都能找到的操作cookie的JavaScript函数:


很遗憾,如果让PHP设定cookie的值为中文,然后让这个JavaScript读取,就会出现乱码:



反之,如果让JavaScript设定了一个中文cookie值,由PHP进行读取,也会出现乱码:



观察上面的乱码,你会发现% u4E2D% u6587刚好是“中文”两个汉字的unicode编码,第一个想法是直接解码,但是PHP里面似乎没有可以把unicode编码转换为汉字的便捷方法。(WordPress倒是不错,不加空格倒是给解码出来了!)

在《JavaScript: The Definitive Guide, 4th Edition》中写到:

In client-side JavaScript, a common use of escape( ) is to encode cookie values, which have restrictions on the punctuation characters they may contain.
在客户端脚本程序中,escape( )函数可以被用作对具有不规范标点的cookie进行编码。(就像我们函数中所用到的一样)

Although the escape( ) function was standardized in the first version of ECMAScript, it has been deprecated and removed from the standard by ECMAScript v3. Implementations of ECMAScript are likely to implement this function, but they are not required to. In JavaScript 1.5 and JScript 5.5 and later, you should use encodeURI( ) and encodeURIComponent( ) instead of escape( ).
虽然escape( ) 已经在ECMAScript中被标准化,但是在ECMAScript v3中,escape( ) 被剔出,如果需要在JavaScript 1.5 和JScript 5.5以后的版本中使用这个函数,建议使用encodeURI( )和encodeURIComponent( )。

按照手册的建议,我修改了JavaScript函数中的escape()和unescape()为encodeURI()和decodeURI(),结果异常的顺利,下面给出修改后的代码和调试程序:







php导出excel文档

while($data_array=mysql_fetch_array($result)){
	$data[$i]=$data_array;
	$i++;
}

$title=array("game_name","des","url","add_time");
$keys=array("game_name","des","url","add_time");

exportToExcel($data,'aa.xls',$title,$keys);

function exportToExcel($data,$filename,$title,$keys){		//$keys為data中要導出的數據列
	header('Content-type: text/cvs');
	header("Content-Disposition: attachment; filename=\"$filename\"");
	$top = '數據導出時間:'.date('Y-m-d H:i:s');
	$table	= '';
	$table .= '';
	foreach($title as $value){
		$table .= '';						//列標題
	}
	$table .= '';
	$i =1;
	foreach($data as $value){
		$table .= '';						//序號
		foreach($keys as $key){									//數據內容
			$table .= '';
		}
		$table .= '';
		$i++;
	}
	$table .= '
'.$value.'
'.$i.''.$value[$key].'
'; $top = iconv('utf-8','gbk',$top); $table = iconv('utf-8','gbk',$table); echo $top; echo $table; exit; }

php下等长截取UTF8中英文混排的字符串

引用地址:http://hi.baidu.com/%D4%C6%CB%AF%C1%CB/blog/item/84ee45eec325d7f2b2fb95a8.html

/**
* 截取指定长度的字符串(UTF-8专用 汉字和大写字母长度算1,其它字符长度算0.5)
*
* @param string $string: 原字符串
* @param int $length: 截取长度
* @param string $etc: 省略字符(...)
* @return string: 截取后的字符串
*/

function cut_str_all($sourcestr, $cutlength = 80, $etc = '...')
{
	$returnstr = '';
	$i = 0;
	$n = 0.0;
	$str_length = strlen($sourcestr); //字符串的字节数
	while ( ($n<$cutlength) and ($i<$str_length) )
	{
		$temp_str = substr($sourcestr, $i, 1);
		$ascnum = ord($temp_str); //得到字符串中第$i位字符的ASCII码
		if ( $ascnum >= 252) //如果ASCII位高与252
		{
			$returnstr = $returnstr . substr($sourcestr, $i, 6); //根据UTF-8编码规范,将6个连续的字符计为单个字符
			$i = $i + 6; //实际Byte计为6
			$n++; //字串长度计1
		}
		elseif ( $ascnum >= 248 ) //如果ASCII位高与248
		{
			$returnstr = $returnstr . substr($sourcestr, $i, 5); //根据UTF-8编码规范,将5个连续的字符计为单个字符
			$i = $i + 5; //实际Byte计为5
			$n++; //字串长度计1
		}
		elseif ( $ascnum >= 240 ) //如果ASCII位高与240
		{
			$returnstr = $returnstr . substr($sourcestr, $i, 4); //根据UTF-8编码规范,将4个连续的字符计为单个字符
			$i = $i + 4; //实际Byte计为4
			$n++; //字串长度计1
		}
		elseif ( $ascnum >= 224 ) //如果ASCII位高与224
		{
			$returnstr = $returnstr . substr($sourcestr, $i, 3); //根据UTF-8编码规范,将3个连续的字符计为单个字符
			$i = $i + 3 ; //实际Byte计为3
			$n++; //字串长度计1
		}
		elseif ( $ascnum >= 192 ) //如果ASCII位高与192
		{
			$returnstr = $returnstr . substr($sourcestr, $i, 2); //根据UTF-8编码规范,将2个连续的字符计为单个字符
			$i = $i + 2; //实际Byte计为2
			$n++; //字串长度计1
		}
		elseif ( $ascnum>=65 and $ascnum<=90 and $ascnum!=73) //如果是大写字母 I除外
		{
			$returnstr = $returnstr . substr($sourcestr, $i, 1);
			$i = $i + 1; //实际的Byte数仍计1个
			$n++; //但考虑整体美观,大写字母计成一个高位字符
		}
		elseif ( !(array_search($ascnum, array(37, 38, 64, 109 ,119)) === FALSE) ) //%,&,@,m,w 字符按1个字符宽
		{
			$returnstr = $returnstr . substr($sourcestr, $i, 1);
			$i = $i + 1; //实际的Byte数仍计1个
			$n++; //但考虑整体美观,这些字条计成一个高位字符
		}
		else //其他情况下,包括小写字母和半角标点符号
		{
			$returnstr = $returnstr . substr($sourcestr, $i, 1);
			$i = $i + 1; //实际的Byte数计1个
			$n = $n + 0.5; //其余的小写字母和半角标点等与半个高位字符宽...
		}
	}
	if ( $i < $str_length )
	{
		$returnstr = $returnstr . $etc; //超过长度时在尾处加上省略号
	}
	return $returnstr;
}

PHP:把字符串中的任意连续字符换成一个对应字符

引用地址:http://www.onlycto.com/tech/2599/46.html


  //1,把字符串中的任意空格换成一个
  $str1 = 'A    B         C   ';
  echo '';
  echo '1:';
  echo preg_replace ("/\s+/", ' ', $str1);
  echo '';
  //2,把字符串中的任意连续字符 M 换成一个 M
  echo '2: ';
  $str1 = 'AMMMBMMMMCMM   ';
  echo preg_replace ("/M+/", 'M', $str1) .'
'; //3,把字符串中的任意连续字符换成一个对应字符 echo '3:
'; $str1 = 'ACCCB CCCCCGGG OOO YYYFFFXXXZZZZZ'; echo $str1 .'
'; $str2 = ''; $i = 0; for ($i=0; $i'; //4,把字符串中的任意连续字符换成一个对应字符 echo '4:
'; $str1 = 'ACCCB CCCCCGGG OOO YYYFFFXXXZZZZZ'; echo $str1 .'
'; $len = strlen($str1); $str2 = $str1[0]; $ch = $str2; for($i=1; $i<$len; $i++){ $ch2=$str1[$i]; if($ch!=$ch2){ $str2.=$ch2; $ch=$ch2; } } echo $str2 . "
"; //5,把字符串中的任意连续字符换成一个对应字符 echo '5:
'; $str1 = 'ACCCB CCCCCGGG OOO YYYFFFXXXZZZZZ'; echo preg_replace("/(.)\\1+/", "[url=file://\\1]\\1[/url]", $str1) .'
';

discuz论坛cdb_threads表displayorder字段含义

http://www.zhaokunyao.com/archives/704

discuz论坛的帖子有不同的状态,例如待审核的,回收站的帖子等,调用时候如何区分帖子不同的状态呢?

可以用cdb_threads.displayorder

1: 本版置顶

2: 本区置顶

3: 全局置顶

0: 正常

-1:回收站中的帖子

-2:待审核的帖子

-3:不清楚