存档在 ‘Web开发’ 分类

跨域获取json数据

2010年7月19日
<!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" >
<head>
    <title>Test Jsonp</title>
	<script type="text/javascript">
        	function jsonpCallback(result)
        	{
			alert(result.msg);
        	}
    	</script>
	<script type="text/javascript" src="http://crossdomain.com/jsonServerResponse?jsonp=jsonpCallback"></script>
</head>
<body>
</body>
</html>

在Firefox中伪造浏览器请求头信息(User-agent)

2010年7月16日
  1. 在地址栏输入”about:config” 然后回车,进入设置页面
  2. 在过滤器中输入”user”,进行选项搜索
  3. 找到”general.useragent.extra.firefox”选项,将该值修改成你所想要的浏览器版本,如”Internet Explorer 8.0″

这样,就实现了http请求头信息中浏览器版本的伪造。

Ecshop二次开发之自定义库文件和模板数据调用

2010年7月14日

Smarty的标签非常多,也比较繁琐,所以Ecshop使用了精简版的Smarty,其中用到的Smarty模板语法:

{$keywords} 输出模板变量
{$array.test.abc} 输出二维数组
{$lang.remark_package} 语言包$lang[remark_package]
{insert_scripts files='common.js'} 引入js文件
<!-- {foreach from=$property_group item=property} -->xxxx<!-- {/foreach} --> 循环
<!-- {if $package_goods_list} -->xxxx<!-- {/if} -->  判断
<!-- #BeginLibraryItem "/library/goods_tags.lbi" --><!-- #EndLibraryItem -->  引入goods_tags.lbi库文件,相当于PHP的include
{*内容*}  html注释,只在模板上显示,页面上会被删除掉.

Ecshop二次开发的数据调用,主要动用到以下两个目录下的文件
dwt(模板文件)路径: themes\default
lbi(库文件)路径: themes\default\library
举个例子就很清楚了,是我从网上找来的,由于转载得很严重,所以不知道真正出处。。
我们在themes\default\library下新建一个名为newest_comments.lbi的库文件,写入以下内容:

if(!function_exists("get_new_comments")){
function get_new_comments($num)
{
   $sql = 'SELECT * FROM '. $GLOBALS['ecs']-&gt;table('comment') .
            ' WHERE status = 1 AND parent_id = 0 and comment_type=0 '.
            ' ORDER BY add_time DESC';
  if ($num &gt; 0)
  {
   $sql .= ' LIMIT ' . $num;
  }
  //echo $sql;
  $res = $GLOBALS['db']-&gt;getAll($sql);
  $comments = array();
  foreach ($res AS $idx =&gt; $row)
  {
   $comments[$idx]['add_time']       = $comments[$idx]['add_time']       = local_date
($GLOBALS['_CFG']['time_format'], $row['add_time']);
   $comments[$idx]['user_name']       = $row['user_name'];
   $comments[$idx]['content']       = $row['content'];
   $comments[$idx]['id_value']       = $row['id_value'];
  }
  return $comments;
}
}
$this-&gt;assign('new_comments',get_new_comments(10)); // 10条最新评论
?&gt;
 
<!--数据调用-最新评论开始 -->
 
 
<div class="comments">
<!--{foreach from=$new_comments item=comment}-->
 
<div class="t_l f_l"><a href="goods.php?id={$comment.id_value}" target="_blank">
    {$comment.content|truncate:15:""}</a></div>
 
 
<div class="d_r f_r">时间:{$comment.add_time}</div>
 
 
<!--{/foreach}--></div>

这样一个库文件就做好了。我们发现,库文件可以使用PHP、Smarty标签和HTML混写的写法,这无疑大大降低了我们二次开发的难度。这个库文件的作用,就是取出数据库中的10条最新评论,并且循环输出到模板。
接下来我们就要在模板中调用这个库文件,我们打开首页的模板themes\default\index.dwt(这里的dwt文件和页面都是一一对应,如商品页是goods.dwt,品牌页是brand.dwt)。我们在首页模板适当的地方加入:

<!-- #BeginLibraryItem "/library/newest_comments.lbi" --> @@@这里即使修改了也没反应@@@<!-- #EndLibraryItem -->

这样就实现了自定义库文件的编写和调用。
细心的你可能会发现,在Ecshop的dwt模板文件中,调用库文件标签<– #BeginLibraryItem “/library/和<– #EndLibraryItem –>之间存在着一些和对应的lbi库文件中重复的内容。你可以把它们当作是注释,用Dreamweaver等编辑器编辑模板时候的需要看见的注释。真正的库文件内容还需要到相应的库文件中去修改。好吧 ,就是这些,简单吧。

[Ecshop]让Smarty不用再写assign

2010年7月14日

由于工作缘故,开始研究起Ecshop的二次开发。从今天起会陆续写几篇关于Ecshop二次开发的文章和大家分享。

Ecshop使用的是Smarty模板引擎——一种被很多人称为“过时”的模板引擎技术(当然,我也是这么认为的)。Smarty作为一种模板引擎技术,使用它的目的是为了实现MVC。而仅仅通过模板技术实现的MVC,还不能成为真正意义上的MVC。Smarty现在也不是PHP官方推荐的模板技术了。不过在官方的框架Zend Framework中,还是保留了对Smarty的支持。

Ecshop的源码中使用了自己精简的Smarty,功能上基本能满足需求。Ecshop仍然是采用面向过程的编码方式,和Discuz类似。而Discuz的中使用模板变量前是不用assign的。那么在Ecshop中像下面的代码我们能不能也省了呢

    $smarty->assign('image_width',  $_CFG['image_width']);
    $smarty->assign('image_height', $_CFG['image_height']);
    $smarty->assign('helps',        get_shop_help()); // 网店帮助
    $smarty->assign('id',           $goods_id);
    $smarty->assign('type',         0);
    $smarty->assign('cfg',          $_CFG);
    $smarty->assign('promotion',       get_promotion_info($goods_id));//促销信息
    $smarty->assign('promotion_info', get_promotion_info());

当然是可以的。我们在Smarty类中的display方法开头加入以下这几句

unset($GLOBALS['_ENV'],$GLOBALS['HTTP_ENV_VARS'],$GLOBALS['HTTP_SERVER_VARS'],$GLOBALS['HTTP_POST_VARS'],$GLOBALS['HTTP_GET_VARS'],$GLOBALS['HTTP_COOKIE_VARS'],$GLOBALS['HTTP_POST_FILES'],$GLOBALS['HTTP_COOKIE_VARS']); //先清空这几个全局变量
$this->assign($GLOBALS); //把全局变量数组"注入模板"

这样,以后在二次开发中我们就不用写那么多繁琐的$smart->assign 了

Thinkphp2.0中关联模型中的一个bug

2010年5月10日

今天天气真好啊。。
在最近一个新项目的开发中,我采用了thinkphp作为开发框架,需求是围绕discuz和uchome进行的二次开发。
我在Conf/config.php配置文件中设置的默认表前缀是”a_”,但由于需求需要,我需要从论坛的”cdb_activitities” 和”cdb_threads”两张表中进行关联查询。按照tp开发手册上所说,我自定义了一下两张表模型的表前缀,并加上关联规则:

/**
 * Activities模型
 *
 * @author xhowhy
 */
class ActivitiesModel extends RelationModel {
    //put your code here
    protected $tablePrefix = 'cdb_';
    public $_link = array(
	'threads'=>array(
	    'mapping_type'=>HAS_ONE,
	    'class_name'     =>'threads',
	    'foreign_key'=>'tid'
       )
    );
}
/**
 * Description of ThreadsModelclass
 *
 * @author Administrator
 */
class ThreadsModel extends RelationModel {
    //put your code here
    protected $tablePrefix = 'cdb_';
}

可关联后进行查询,发现class_name返回的是bool(false)。我很奇怪,就算是没有被关联的数据,那返回的也应该是null,怎么会是bool(false)。后来经过查看tp源码中的Thinkphp/Lib/Think/Core/Model/RelationModel.class.php文件,终于在170行找到原因:

                        // 获取关联模型对象
                        $model = M($mappingClass);

可以看出,在生成关联模型对象的时候,源码中采用了M函数,而在Thinkphp/common/function.php中定义的M函数的作用是“M函数用于实例化一个没有模型文件的Model”。很显然,根据上下文,这里应该使用D函数。因为就算是关联模型,也不一定没有模型文件,同样有可能是自定义表前缀、甚至是跨库操作。
所以代码应该改成:

                        // 获取关联模型对象
                        $model = D($mappingClass);

问题成功解决了。

跟踪客户需求变更和虚惊一场

2010年4月10日

本来题目里说的是两件事的,合在一篇里写,足以见证这一周的tough。

先说第二件事,其实和第一件也有关系。根据客户的需求,修改了index.html页面。本应该上传到/templates下,却一不小心上传到网站根目录/,把客户原本的flash首页给覆盖了。这下心想over了,俊哥那应该没有存底的,只好自己做一个吧,embed标签还是会的。

刚用编辑器建立一个新的html文件,要先写上keywords和description,就用google百度了一下客户的网站,看到了一句短短的描述。下意识的点了链接,发现点开的竟然不是index.php而是index.html的flash首页!Oh~搜狗浏览器威武~看来是搜狗把页面和域名都缓存了缘故。查看源代码,ctrl+c,Ctrl+v,Ctrl+s。。

(我们也可以通过查看网页快照找回从前的页面源代码,前提是你的站点被收录了)

吸取教训:1、以后静态首页扩展名用.htm,模板文件用.html或者.php,避免覆盖;2、或者首页模板文件不叫index.html而叫做default、Homepage;3、不管怎样,以后上传文件多加小心,合理给文件命名,最大程度避免杯具的再次发生。

说第一件事。

去年做的单子,客户是自动控制行业的一家公司。最近,原本负责他们公司网络的网管员(也是负责他们公司网站建设的人)走人了。新上任的这一位网管貌似有点想法,一直在联系我,前后提出了一些更改方案,主要的修改是把产品分类从三级增加到5级,我按他的要求做了。完了之后,说还是不完善,又提出让我过去当面沟通。

见面之后,我很诧异他竟然是个男的,电话里我一直以为是个御姐~o(∩_∩)o 哈哈。交流过程中,我发现他们走人的那位似乎工作交接没有做到位,这位新的网管简直是完全不知所以然,连个后台地址用的都是测试时候用的虚拟主机四级域名(年前就弃用了)。。

我向他展示了新后台的使用方法后,他倒是气定神闲提出了很多前台页面的修改需求,还不忘讽刺他那位前同事接手的这件事(网站建设)没做好。我当即表示,一开始需求就是你们客户提出的,另外我们对你们行业也不甚了解,自然要按照你们客户的需求来做。现在你觉得没有满足你的需求,那也正是说明当初你根本没弄清楚自己的需求,责任不在于我们开发人员。可以说,现在的情况是你们需求产生变动,不是我们当初没把你们需求做好。

他哪里知道,他提出的几点修改需求,足以让我让我和俊哥把产品分类推到重做,况且我之前花在产品分类和其他一些地方上的修改已经很多了。

我和俊哥说了,他说没事,需求变动大就要他们加钱。谁知过两天之后,客户又打来电话说,我给你个网站地址,你就照着上面的来做。。看了看  说行

前后两天的努力,总算按客户的意思做好了,前台页改得面目全非,动用到了数据表结构变更,url更是重新设计,分类列表的递归输出。。不过还好,最后终于上线了。

这次的事让我体会到跟踪客户需求变更的重要性,因为有时候,用户只是简单的一句话,对于项目的调整来说工作量是非常巨大的。。在项目的初期,我们应该先调研,帮客户弄清需求,并考虑将来可能遇到的需求变动;在适当的时候,我们可以让客户知道需求变更的代价。

通过这个项目,也开始有点体会到“随着 Web 应用程序变得越来越复杂,简单的 CRUD 操作已经无法满足对于复杂应用程序的开发要求。”接下来,要好好学习一下软件工程,并把面向对象的程序设计和实现运用到新项目当中去。。

回顾一下曾经开发过的 PHP 应用,大部分开发者都会发现这些应用中,数据的创建、读取、更新和删除操作是重复最多次的操作。但是不管我们如何简化这些 CRUD(创建、读取、更新、删除)操作,面对客户不断变化的需求,应用程序的内在结构总是逐渐变得凌乱。

而造成这种情况的根本原因就是我们没有正确使用面向对象的技术来设计和实现这些应用程序。由于业务逻辑固有的复杂性被所谓的 CRUD 快速开发能力所掩盖。本应是内聚的业务逻辑却拆散为一个个 CRUD 操作,分散到了应用程序的不同部分。如此一来,业务逻辑的变化必然会导致应用程序内部产生连锁反应式的改动,应用程序内在结构的逐渐腐朽变成了不可逆转的趋势。

不知道会不会怪我。。

2010年4月4日

这一周竟然一篇日志都没写。。懈怠了懈怠了。唉

昨晚用Thinkphp搞了个后台,剽窃了 pbdigg的模板 ,不知道会不会怪我 ,唉

Thinkphp设计得很好,很多地方都替开发者考虑得周全了。。比如第二张图中的?m=admin上两张图:

他会提示:

系统发生错误

您可以选择 [ 重试 ] [ 返回 ] 或者 [ 回到首页 ]

[ 错误信息 ]

非法操作admin

[ TRACE ]

[10-04-04 11:38:04] () Action->__call(admin, Array)
[10-04-04 11:38:04] () LogAction->admin()
[10-04-04 11:38:04] F:\wwwroot\libra\lib\ThinkPHP\Lib\Think\Core\App.class.php (415) call_user_func(Array)
[10-04-04 11:38:04] F:\wwwroot\libra\lib\ThinkPHP\Lib\Think\Core\App.class.php (439) App::exec()
[10-04-04 11:38:04] F:\wwwroot\libra\admincp.php (11) App::run()

真好。。

让PHP支持像jQuery那样的链式操作

2010年3月19日

群里有人讨论这个问题,我的想法是在方法里返回this指针(指向对象本身),通过对私有成员$sql的赋值,来获得最终的执行语句,并返回相应结果。

Class Database{
    private $sql;
...
    public function where($condition){
        //此处省略n行...
        return this;
    }
    public function limit($limit){
        //此处省略n行...
        return this;
    }
    public function execute(){
        return this->query($sql);
    }
    public function select(){
        //此处省略n行...
        return this;
    }
}
//调用时:
$DB = new Database();
$DB->where($condition)->limit(20)->select();

用NoSQL替代MySQL ?

2010年3月15日

今天看到一条消息,说Digg要和Mysql说再见了。

这本来是无可后妃的。DBMS只是用来管理数据的,做统计、经营分析之类的事情。这个任务往往要求不是实时的。高速存取也不是它的强项,信道是有限的。RAM Cache虽然快但是硬件成本不说,它不够稳定,特别是对事物控制。所以出现了 noSql这一说法,这是必然趋势。

可以遇见,ram cache与noSql同步关系,noSql与dbms异步关系。noSql不是对DBMS的替代。作用为减轻业务库压力,提高前端响应、即时数据共享。这些都是在保证事务,数据稳定前提下进行的。

我预见的RIA未来

2010年3月12日

像我看齐,起一个幽默一点的标题吧。

下面是我用Google Trends搜索到的Flex和Extjs两项RIA技术的关注度对比。可以看出,Flex在全世界关注程度远超Extjs啊。。这两门RIA技术分别代表了两个阵营——以flex、sliverlight为代表的基于runtime的表示层技术和以javascript为代表的浏览器脚本技术。

flex extjs

据我所知,Extjs目前还没有一个完善的可视化编辑器,所有的页面呈现必须自己编写代码,这是比较蛮烦的。。而Flex有一个相对比较完善的可视化编辑器,基于flash技术的UI组件也比extjs要丰富和完善,(毕竟Adobe是大公司 实力雄厚哇),世界上95%以上的PC机上装有flash插件,而flex正是基于flash。

无论还是js还是flash,都是这个世界的浏览器中支持得最广泛的技术。Extjs的代码显然更易学一点(基于javascript),但UI构建上比较欠缺;反观Flex,有一个趋于完善的开发环境,但其mxml和actionscript脚本显然学习成本较高。所以他们是各有所长吧。但就google趋势上来看,Adobe的拥趸者明显多一些,所以学习资料自然多一些——这一点我已经到学校图书馆考证过了。。

那么再看一下最近颇为火爆、被称为RIA杀手的HTML5与前面两项技术的对比吧:

flex extjs html5

但是HTML5怎么可能成为RIA杀手呢,仅因为几个<video>、<canvas>之类的标签吗?大家都知道,flash、sliverlight和JavaFx和浏览器的关系,一直都是插件和平台的关系(Extjs是例外)——HTML5显然还没有强大到可以集成那么多的UI组件,比如DataGrid、List、Tree等。可见啊。HTML5和RIA是会共存下去的。那么至于Flex和js究竟哪一个才会成为RIA开发的真正主流呢,市场会说明一切的。我看好Flex。