完善了一下博客程序

完善了下博客程序,修正了几个BUG,主要是面向用户的前台功能:

1、将博客分页由之前的“上一页/下一页”的外观,修改成了目前的数字分页。主要参考的是这个Digg-like的分页方法

2、修改了友情链接提交页的一个BUG,感谢桂网(我的本科校友)的提交。

3、增强了用户评论功能,默认用cookie保存用户基本信息,不用重复输入。

4、修改了首页“最新留言”的表现样式,主要是受华晨移植千鸟志皮肤的启发,再次一并感谢。

刚才看到华晨关于Trackback留言,我又发现了一个BUG,或者说不是BUG,是我功能没做完。那就是Trackback功能竟然没完成,博客访问量很低,一直忽视了这个问题。目前,大家可以PING到我的博客来,但是我在后台还审核不了,因为没有做这个功能,但数据都在数据库里面,囧。下次心血来潮了补上,最近比较忙。

Tags: 博客,程序

修改了几个BUG,图标吾爱升级版本0.1.1

这几天抽空对图标吾爱的源码进行了完善,主要以解决BUG和算法升级为主。

具体升级细节Ver 0.1.1:

1、开启整站GZIP压缩

2、修正ICO图标下载失败的BUG

3、整合多个CSS文件至单一CSS文件

4、重写搜索、分词、智能提示(?)的核心算法

5、压缩所有JS CSS文件

6、检查整站是否存在安全漏洞

7、加入DB Cache功能

总的来说,是在做性能优化,不过由于主机用到是IXWebHosting,国内访问速度还是慢。等有空了,开始租用国内的LINUX主机,做下调查先。

下一步将直接升级到Ver 0.2,以功能升级为主:

1、加入Favicon在线生成

2、加入图片格式在线转换

使用索引优化含ORDER BY的MySQL语句

谨以此文献给那些希望优化MySQL数据库查询性能,却又不知道如何着手的同仁们。本文将持续更新

本文的第一个版本发布在CI中国社区,主要是发现很多同学虽然知道索引能够提升MySQL数据库的读取性能,但却存在很多操作上的误区。所以,我特此写了这篇文章,希望能够对大家有些启示。

下面的内容很大程度上是我在平时项目中积累所产生的认识,既然是一家之言,难免会有错误。如果对其中某一条规则有异议,欢迎和我交流。

在开始之前,我想表明一个观点,很多同学在编写WEB程序时,往往非常重视程序的结构和效率,这固然是一个很好的习惯。但他们却忽视了对数据库的结构和优化。在我看来,对于目前很多网站来说,特别是那些对数据库依赖非常严重的泛WEB 2.0网站,数据库调优比程序本身的效率更重要。

本文的主题是:在MySQL中,如何通过合理的建立索引,大幅提升包含ORDER BY语句的效率。在这里,我主要以讲述操作为主,至于为什么这么做,各位同学就要去查阅包括MySQL手册在内的其他资料了。

»阅读全文

PHP设计模式:工厂模式之抽象工厂

上一篇中,我主要记录了工厂模式之一的简单工厂在PHP中的实现,这篇文章主要总结工厂模式的另一种形态:抽象工厂。

简单工厂中,工厂的角色是负责实例化具体对象,而在实际应用中这种情况却不很实用,主要原因是如果我们希望增加或去除这个工厂所能实例化的某个对象,则需要对工厂类进行直接修改,这显然违背了低耦合的宗旨。对于上一篇文章的例子来说,那就是:如果我们需要添加那个汽车工厂所能生成的汽车品牌,则需要修改工厂类的判断逻辑。

如何尽可能的降低耦合,从而达到非侵入式的设计逻辑?这里的非侵入式一次,是我从Spring中借用过来的概念,通俗来讲,就是去除和添加某个工厂的产品对象不影响整个程序的架构。

由此就引入了抽象工厂的思想。抽象工厂将面向接口编程的思想演绎的淋漓尽致,它的核心思想是:抽象工厂仅提供一个产品簇(同一类别的所有对象的接口抽象)的通用接口,而将实例化对象的任务交给遵循其标准的具体工厂来完成;具体工厂还可能生产出多个产品,此时还需要对产品定义一个接口,供具体工厂来生产具体产品。

举个例子,还是关于生产汽车的。汽车工厂经过一段时间的努力,现在已经发展装大了,于是做了两个决定:第一个决定是将生产汽车的过程分拆成两个阶段,分别是生成轮胎和除去轮胎的其他部分。另一个决定是,决定为每个汽车品牌单独建立一个汽车工厂。那么如何管理这些工厂,使他们既遵循第一个决定,又不相互干扰?解决办法就是:汽车总厂提供生产汽车的通用流程(第二条),这个流程两个子工厂都需要严格执行。同时,将具体生产的过程交给两个具体工厂,分别是Benz工厂和Audi工厂。这就是抽象工厂的设计思想的概念。

»阅读全文

PHP设计模式:工厂模式之简单工厂

要写出漂亮的代码,掌握一些常用的设计模式是很有必要的。这篇文章只是我将设计模式应用在OO PHP的系列学习(之前一直是在JAVA里面)笔记之一,如有不妥,就留言一起探讨。

根据设计模式的圣经GoF所写的Design Patterns: Elements of Reusable Object-Oriented Software一书的分类,工厂模式被归类在创建模式(Creational Pattern)之下。工厂模式作为一种创建模式,主要用于处理对象的创建,以适合不同场景[via]。

工厂模式又分为抽象工厂模式和工厂方法模式。

本文所讨论的简单工厂,又称作静态工厂方法,可以看作是工厂方法的一个特例。个人认为它是学习工厂模式最好的切入点。

工厂模式,正如其名,我们在实例化一个对象时,不是直接实例化具体的对象,而是通过工厂这个接口来实现。通俗的说,作为消费者(某个对象A),我们在需要消费(调用)某个具体产品(其他对象B)时,不需要了解这个产品(对象B)的制作过程(实现过程),只需要直接拿这个产品来用即可。而具体的这个产品的生成(对象的实例化)过程,由工厂实现。

可见,工厂模式可以在降低对象间的关联(耦合度降低),并能够隐藏具体产品的实现过程。因为整个调用过程是面向接口的。

»阅读全文

新项目:图标吾爱上线

图标吾爱,一个中文图标搜索引擎。

这个网站是我前不久花了断断续续一个多月时间策划和编码制作出来的新站,没有预期它能给我带来多大的作为,仅作为编程的练手以及积累网站运营的经验。

当然,做这个图标搜索站也是有目的性的。

我发现目前国内虽然关于素材的站点很多,但它们普遍存在以下几个问题:

1、图标质量低下。

2、没有对图标进行很好的分类和索引,这就会导致:用户可能仅仅需要搜索某个特定图标,但由于网站没有提供一个良好的索引和检索方式,导致用户需要花费大量的时间和精力浏览很多并不相关的页面,分散注意力,效率低下。

3、用户体验不够好。这实际上是上面说的第二点相关联。

4、不尊重版权。这是一个开放的互联网时代,不尊重版权就意味着杀鸡取卵,自断后路。

图标吾爱的出发点就是改进上述不足,以增强用户体验为主。稍后还会推出一系列与图标处理相关的服务,比如Favicon生成、在线格式转换等非常实用的功能。

图标吾爱总的设计思想是:为每个图标添加多个元标记,我称之为meta tag,然后将此标记与每个图标相关联。而元标记的添加,我采用了开放的理念,由用户自行添加,后台审核。当元标记足够多足够精确之后,检索的质量就自然提高了。

我的目标是,在10秒之内,让用户搜索到自己期望的图标

目前图标吾爱租用的是美国的服务器,可能速度较慢,稍后会将它转移到国内的IDC上,正式运行。

最后,希望有兴趣的朋友,和我共同维护这个项目。要求只有一个:不是奔钱而来的,对网站维护有一定经验(这个网站正处于并将长期处于赔本阶段)。

使用XSLT进行日期格式转换

现在有个问题需要用XSLT来实现,那就是在XSLT中如何将一个日期结点的格式由YYYY-MM-DD转换到DD/MM/YYYY?

我首先想到的就是利用XSLT中的带参数的模板,将此原始日期作为参数参数一个模板中,然后进行重新组合。说起来晕乎乎,还是直接进入实战吧。

假设现在有一个XML文档,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="format_date.xsl"?>
<notebooks>
 <notebook>
  <title>红花还需绿叶衬,我是标题一</title>
  <date>2009-08-11</date>
 </notebook>
 <notebook>
  <title>红花还需绿叶衬,我是标题二</title>
  <date>2009-08-10</date>
 </notebook>
</notebooks>

在这个文档中,结点的日期为2009-08-11,即格式为YYYY-MM-DD,现在我们需要利用XSLT将其转换成DD/MM/YYYY,也就是11/08/2009。

关于实现思路,我在上面已经讲到,不再赘述。这里讲讲具体实现,一个带参数的XSLT模板:

<xsl:template name="FormatDate">
 <!--Convert Old Date Format:yyyy-mm-dd to New Date Format: dd/mm/yyyy-->
 <xsl:param name="DateTime" />
 <xsl:variable name="y">
      <xsl:value-of select="substring($DateTime,1,4)" />
    </xsl:variable>
    <xsl:variable name="m_temp">
  <xsl:value-of select="substring-after($DateTime,'-')" />
 </xsl:variable>
    <xsl:variable name="m">
      <xsl:value-of select="substring($m_temp,1,2)" />
    </xsl:variable>
    <xsl:variable name="d_temp">
      <xsl:value-of select="substring-after($m_temp,'-')" />
    </xsl:variable>
    <xsl:variable name="d">
      <xsl:value-of select="substring($d_temp,1,2)" />
    </xsl:variable>
    <xsl:value-of select="$d"/>
    <xsl:value-of select="'/'"/>
    <xsl:value-of select="$m"/>
    <xsl:value-of select="'/'"/>
    <xsl:value-of select="$y"/>
</xsl:template>

如果对XSLT有所了解,相信上面的代码非常直观;如果不太了解,那么首先你应该去了解,或者在下面留言……

在XSLT中,我一直将模板当作其他程序语言中的函数。理解了这一点,上面这段程序就很好理解了,那个参数Datetime就像是程序语言中的入口参数,用来接受外部送给这个“函数”的参数。

需要注意的地方是,上面的19-23行,这是最后对日期各个部分(年、月、日)进行组合。换言之,你可以组合出任意你可以想出的日期格式,不限于此。

但这里只写了“函数”了部分,没有提到调用,调用方法如下:

<xsl:call-template name="FormatDate">
 <xsl:with-param name="DateTime" select="date"/>
</xsl:call-template>

在此例中,我将date这个结点的值传给了“函数”的参数。

完整的XSLT文件和最后的结果请分别这里这里

CodeIgniter中开启PATH_INFO时mod_rewrite隐藏index.php的问题

我曾专门写过一篇文章介绍如何使用mod_rewrite隐藏URL路径上的index.php,但在某种情况下如果你改变了URI寻址的方式,这份htaccess方案可能会失效。

在CodeIgniter中,当我将URI寻址方式从AUTO更改为PATH_INFO时,即:

$config['uri_protocol'] = 'PATH_INFO';

注:PATH_INFO的开启,是因为我希望通过$_GET来取值,而不是系统默认的POST方式。

在此情况下如何仍然使用以上.htaccess方案,结果将是:index.php顺利隐藏,但主控制器并不能正确的获取值。

解决方案如下,就一步:

去掉以下重写规则中index.php后面的问号即可。

 RewriteRule ^(.*)$ /index.php?/$1 [L]

修改后的规则如下:

 RewriteRule ^(.*)$ /index.php/$1 [L]

其他地方不变。

Why?

第一句话在index.php后加问号的意思是告诉Apache的mod_rewrite模块,处理请求时自动去掉index.php后的GET字符串,这显然与我的意图相悖。

Yahoo有Bing:Yahoo Boss和Search Monkey服务将会被保留

作为一名开发人员,我并不太关心雅虎作为一个搜索引擎的垂垂老矣,以及他们与微软所作出的交易。It's none of my business.

我所关心的是作为雅虎搜索API旗下的Yahoo! Search Web Services是否会被中止?如果被中止,对于基于此API的应用程序或者希望使用Yahoo Search API接口的开发人员将是一个噩梦。

虽然可能在搜索技术和业务推广上不如Google,但是在“开放”这个话题上,雅虎绝对是一个令人尊敬的公司。你可以通过各大搜索引擎对于其搜索API的重视和开放程度来审视这一观点:

对于开发者来说,Yahoo的Yahoo BOSSYahoo Search Monkey在开发灵活度上要远比Google AJAX Search要开放很多;后者主要提供基于前端AJAX封装的搜索功能,可以说,这不是真正意义上的Web Service。

05年以前,Google还提供基于SOAP的Search API,不过目前这个API已经被中止。有些许值得欣慰的是,Google目前的AJAX Search增加了JSON回调数据的接口,但就算如此,开发性仍然比不上Yahoo Search API。

至于国内的百度,就不提了,似乎从来没有,也不打算提供基于中文搜索的API服务。或许百度压根就不是一个以技术为驱动的公司,而是一家营销公司。

废话不多说,那么到底在Bing和雅虎的交易过后,雅虎目前的API是否会保留?我们可以从TechCrunch的这篇文章中了解到:

Microsoft will also become the new home for Yahoo’s search technologies. That is a good thing because even before this deal was announced, the spirit of technology innovation at Yahoo which produced projects such as Yahoo Boss and Search Monkey seems to have fizzled. These efforts will now be passed on to Microsoft. The fortunate news is that Mehdi says he wants to keep those projects alive. “For Search Monkey and Boss, we will integrate that technology and determine how to take that forward. There is a lot of goodness there.” At least Microsoft knows a good developer platform when it sees one.

可见,Search Monkey和BOSS都将被保留,但如何发展,就得看微软的整合能力了,不过这一点应该不用太担心。

MySQL:快速随机选取一条记录的思考

本文讨论的是如何从MySQL一个数据表中提取一条随机的效率,同时要保证效率最高。

方法一

这是最原始最直观的语法,如下:

SELECT * FROM foo ORDER BY RAND() LIMIT 1

当数据表中数据量较小时,此方法可行。但当数据量到达一定程度,比如100万数据或以上,就有很大的性能问题。如果你通过EXPLAIN来分析这个语句,会发现虽然MySQL通过建立一张临时表来排序,但由于ORDER BY和LIMIT本身的特性,在排序未完成之前,我们还是无法通过LIMIT来获取需要的记录。亦即,你的记录有多少条,就必须首先对这些数据进行排序。

方法二

看来对于大数据量的随机数据抽取,性能的症结出在ORDER BY上,那么如何避免?方法二提供了一个方案。

首先,获取数据表的所有记录数:

SELECT count(*) AS num_rows FROM foo

然后,通过对应的后台程序记录下此记录总数(假定为num_rows)。

然后执行:

SELECT * FROM foo LIMIT [0到num_rows之间的一个随机数],1

上面这个随机数的获得可以通过后台程序来完成。此方法的前提是表的ID是连续的或者自增长的。

这个方法已经成功避免了ORDER BY的产生。

方法三

有没有可能不用ORDER BY,用一个SQL语句实现方法二?可以,那就是用JOIN。

SELECT * FROM Bar B JOIN (SELECT CEIL(MAX(ID)*RAND()) AS ID FROM Bar) AS m ON B.ID >= m.ID LIMIT 1;

此方法实现了我们的目的,同时,在数据量大的情况下,也避免了ORDER BY所造成的所有记录的排序过程,因为通过JOIN里面的SELECT语句实际上只执行了一次,而不是N次(N等于方法二中的num_rows)。而且,我们可以在筛选语句上加上“大于”符号,还可以避免因为ID好不连续所产生的记录为空的现象。

还有更好的方案吗?有待总结。

Tags: mysql,效率