blog域名迁移之迁移wordpress

This item was filled under [ wordpress tips ]

迁移wordpress主要涉及到3步:

1、数据备份

如果服务器上装有phpmyadmin,可以直接导出一下。使用shell的朋友,可以用如下命令来备份数据:

mysqldump  -u dbuser -pdbpass -h  dbhost  dbname | gzip > backup.sql.gz

把相应位置的dbuser, dbpass, dbhost和dbname替换为数据库用户名、密码、数据库服务器以及要备份的库名。最后得到的backup.sql.gz,就是一份完整备份。

插一句,我把备份的文件解压一看,居然有12M之巨。如果10%是有效内容的话,我这4年已经写了1.2M字节,相当于60万汉字了。

2、配置Web服务器

在这里需要牢记一点:使用301跳转,而不要用默认的302refer)。

配置Web服务器的目的是,将访问原有域名的请求引导到新的域名。301跳转是永久重定向,而302跳转是暂时重定向。前者对搜索引擎更为友好。

在nginx中做如下配置:

server {
listen   80;
server_name  oldhost.com www.oldhost.com newhost.com;
rewrite ^/(.*) http://www.newhost.com/$1 permanent;
}

server{
listen  80;
server_name  newhost.com;
……
}

第一段的配置是将oldhost.com,www.oldhost.com,newhost.com的请求都重定向到www.newhost.com 下面。而第二段是用www.newhost.com替换原有的www.oldhost.com,其他部分不用改变。注意到在使用rewrite时,加入了 permanent关键字,可以使nginx发送301重定向。

如果使用apache,配置也类似,在rewrite时可加入参数R=301。

保存之后重启web服务器,使配置生效。

3、修改数据库

这也是对wordpress进行迁移的最后一步。需要注意,在完成第二步之后,wordpress会暂时无法打开,原因大家可以自己考虑一下。如果觉得不太好,把这一步提到前面也可以。或者可以先修改好配置文件,等第三步完成了再重启web服务器。

修改数据库主要修改3部分,语句可以在phpmyadmin或者mysql命令行中进行,整理自此处

(1)修改站点地址、主页地址:

UPDATE wp_options SET option_value = replace(option_value, ‘http://www.old-domain.com’, ‘http://www.new-domain.com’) WHERE option_name = ‘home’ OR option_name = ’siteurl’;

(2)修改文章中内部链接以及附件地址:

UPDATE wp_posts SET post_content = replace(post_content, ‘http://www.old-domain.com’, ‘http://www.new-domain.com’);

(3)更新文章永久链接:

UPDATE wp_posts SET guid = replace(guid, ‘http://www.old-domain.com’,’http://www.new-domain.com’);

这三板斧一过,wordpress的迁移已经完成了。之后就从新域名打开网站,看看是否还有什么地方遗漏未能改掉。

BTW,如果原来域名有备案的话,可以在页面底部去掉。更换域名以后,就失效喽。

Bookmark and Share

GAE中数据库列表的值为其他实体的方法

This item was filled under [ 易懂python ]

处理Tag(标签)和Diary(日志)时出现了问题,因为GAE并没有多对多关联,经过查询资料,可以有一种很简单的办法是在关系的其中一方创建一个的列表,如下:

class Tag(db.Model):
name = db.StringProperty( required = True )
diaries = db.ListProperty(db.Key)

class Diary(db.Model):
title = db.StringProperty( required = True )
content = db.TextProperty()
category = db.ReferenceProperty(Category)

@property
def tags(self):
return Tag.gql(“WHERE diaries = :1″, self.key())

在一篇日志(Diary)贴上标签(Tag)用如下办法即可:tag.diaries.append(diary.key())

获取一篇日志(Diary)的标签(Tag)用diary.tags()即可

这样就比较简单的实现了多对多的关联

欢迎交流:ljy080829@gmail.com

Bookmark and Share
Tagged with: [ , , ]

使用ghost-blog,让你的wordpress成为一个超级cms

This item was filled under [ wordpress plugins ]

这个插件可以让你的blog有个ghost功能,如果你想创建一个cms,比如类似学校课程的列表,会按照不同专业列出课程,不同的专业可能会有相同的专业课或选修课程,这个时候,你可以建多个文章标题比如: 

website

-php

–wordpress

-html

–wordpress(for designer)

 

此时,你可能想要2个跟wordpress的文章的内容一样,并且,改变其中一个的时候,另一个也同时改变,就像是一篇文章的内容,可以放到2个文章里一样。

在你想ghost的blog内容里写上你要ghost的文章id即可类似如此: [ghost=897]

这样插件就会自动获取id为897的文章的内容。

 

This plugin would let your blog got a ghost function,just like if you want to create a cms system,like a course list for different specialities,but for different specialities,there must be some courses would be the same,for then,you could create different blog post or page to to this:

website

-php

–wordpress

-html

–wordpress(for designer)

 

Then, you maybe want two of the wordpress course got the same content, and when you change one of the content,then all of the other content would be change,just like you put one content in two blog posts.

Check out the plugin URL, for more information.

Put the tag into the new post that you want to ghost: [ghost=897]

Then the plugin would automaticly get the content of the post 897(the post id) to the new blog you want to be show

Bookmark and Share

Python字符串的encode与decode研究心得乱码问题解决方法(转载 )

This item was filled under [ 易懂python ]

为什么Python使用过程中会出现各式各样的乱码问题,明明是中文字符却显示成“\xe4\xb8\xad\xe6\x96\x87”的形式?

为什么会报错“UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-1: ordinal not in range(128)”?本文就来研究一下这个问题。


字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。

decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode(‘gb2312′),表示将gb2312编码的字符串str1转换成unicode编码。

encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode(‘gb2312′),表示将unicode编码的字符串str2转换成gb2312编码。

因此,转码的时候一定要先搞明白,字符串str是什么编码,然后decode成unicode,然后再encode成其他编码


代码中字符串的默认编码与代码文件本身的编码一致

如:s=’中文’

如果是在utf8的文件中,该字符串就是utf8编码,如果是在gb2312的文件中,则其编码为gb2312。这种情况下,要进行编码转换,都需 要先用decode方法将其转换成unicode编码,再使用encode方法将其转换成其他编码。通常,在没有指定特定的编码方式时,都是使用的系统默 认编码创建的代码文件。

如果字符串是这样定义:s=u’中文’

则该字符串的编码就被指定为unicode了,即python的内部编码,而与代码文件本身的编码无关。因此,对于这种情况做编码转换,只需要直接使用encode方法将其转换成指定编码即可。


如果一个字符串已经是unicode了,再进行解码则将出错,因此通常要对其编码方式是否为unicode进行判断:

isinstance(s, unicode) #用来判断是否为unicode

用非unicode编码形式的str来encode会报错


如何获得系统的默认编码

#!/usr/bin/env python
#coding=utf-8
import sys
print sys.getdefaultencoding()

该段程序在英文WindowsXP上输出为:ascii


在某些IDE中,字符串的输出总是出现乱码,甚至错误,其实是由于IDE的结果输出控制台自身不能显示字符串的编码,而不是程序本身的问题。

如在UliPad中运行如下代码:

s=u”中文”
print s

会提示:UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-1: ordinal not in range(128)。这是因为UliPad在英文WindowsXP上的控制台信息输出窗口是按照ascii编码输出的(英文系统的默认编码是ascii),而上面代码中的字符串是Unicode编码的,所以输出时产生了错误。

将最后一句改为:print s.encode(‘gb2312′)

则能正确输出“中文”两个字。

若最后一句改为:print s.encode(‘utf8′)

则输出:\xe4\xb8\xad\xe6\x96\x87,这是控制台信息输出窗口按照ascii编码输出utf8编码的字符串的结果。


unicode(str,’gb2312′)与str.decode(‘gb2312′)是一样的,都是将gb2312编码的str转为unicode编码

使用str.__class__可以查看str的编码形式


原理说了半天,最后来个包治百病的吧:)
#!/usr/bin/env python
#coding=utf-8
s=”中文”
if isinstance(s, unicode):
#s=u”中文”
print s.encode(‘gb2312′)
else:
#s=”中文”
print s.decode(‘utf-8′).encode(‘gb2312′)

Bookmark and Share

wordpress help sheet,wordpress实用帮助小抄[持续更新中]

This item was filled under [ wordpress tips ]

get_post_custom()
Get all key/value data for the current post.
get_post_custom_keys()
Get a list of all key names for the current post.
get_post_custom_values($key)
Get the list of values for a particular key on the current post.
get_post_meta($post_id, $key, $single = false)
In WP 1.5 and beyond, this function returns the meta information without cache problems. The function requires the post id, the key, and if $single is set to TRUE, it returns only the first result (NOT as an array) for PHP use.

忘记admin密码,可以这样
修改MD5密码为:”5d41402abc4b2a76b9719d911017c592″,然后使用“hello”登录
得到的字符串,就是加密后的admin。在phpmyadmin里更新下admin帐号的密码为这个新的字段

获取图片地址:

$search = ‘/<img[^\>]*src=\”(.+?)\”.*\/>/’;

$img_arr = ”;

if (preg_match_all($search, $content, $matches, PREG_SET_ORDER))

{

foreach ($matches as $match)

{

$img_arr[] = $match[1];

$content = str_replace($match[0], ”, $content);

}

}

wordpress迁移,数据库修改语句

UPDATE wp_options SET option_value = replace(option_value, ‘old’,'new’) WHERE option_name = ‘home’ OR option_name = ’siteurl’;

UPDATE wp_posts SET post_content = replace(post_content,’old’,'new’);

UPDATE wp_posts SET guid = replace(guid, ‘old’, ‘new’);get_post_custom()
Get all key/value data for the current post.
get_post_custom_keys()
Get a list of all key names for the current post.
get_post_custom_values($key)
Get the list of values for a particular key on the current post.
get_post_meta($post_id, $key, $single = false)
In WP 1.5 and beyond, this function returns the meta information without cache problems. The function requires the post id, the key, and if $single is set to TRUE, it returns only the first result (NOT as an array) for PHP use.

忘记admin密码,可以这样
修改MD5密码为:”5d41402abc4b2a76b9719d911017c592″,然后使用“hello”登录
得到的字符串,就是加密后的admin。在phpmyadmin里更新下admin帐号的密码为这个新的字段

获取图片地址:

$search = ‘/<img[^\>]*src=\”(.+?)\”.*\/>/’;

$img_arr = ”;

if (preg_match_all($search, $content, $matches, PREG_SET_ORDER))

{

foreach ($matches as $match)

{

$img_arr[] = $match[1];

$content = str_replace($match[0], ”, $content);

}

}

wordpress迁移,数据库修改语句

UPDATE wp_options SET option_value = replace(option_value, ‘old’,'new’) WHERE option_name = ‘home’ OR option_name = ’siteurl’;

UPDATE wp_posts SET post_content = replace(post_content,’old’,'new’);

UPDATE wp_posts SET guid = replace(guid, ‘old’, ‘new’);

博客换地址后,解决You do not have sufficient permissions to access this page.的问题。

UPDATE `prefix_usermeta` SET `meta_key` = REPLACE( `meta_key` , 'wp_', 'prefix_' );

(Make sure you do backups first! Note that the quotes used for string and field name are different.)

In the options table, there is ‘wp_user_roles’, make sure you get that changed into ‘prefix_user_roles’.

UPDATE `prefix_options` SET `option_name` = 'prefix_user_roles' WHERE `option_name` ='wp_user_roles' AND `blog_id` =0;

Bookmark and Share

wordpress永久链接格式建议

This item was filled under [ wordpress tips ]

wordpress永久链接用什么格式比较好?

其实这个问题没有统一的答案,因为各有各的说法,如果一定要一个确切的答案,那么我就给出两个永久链接格式建议:

  1. /html/%postname%.html
  2. /html/y%year%/%post_id%_%postname%.html

首先我来说说第一种永久链接格式的好处:

  1. 路径比较浅,所有的post都在html目录下,有利于SEO;
  2. 结尾是html,当今后访问量急剧上升,可以使用cos-html-cache静态化,由于都是在目录html,静态化之后不至于搞乱wordpress本身程序目录;
  3. 个人blog,假设可以坚持10年,一天一篇日志,也不过3000多篇日志,所以即使静态化,html目录下也仅仅不到10000个文件,不足以影响磁盘I/O效率;

相比之下,第二种永久链接的格式的优点在于,即使一年上万日志的静态化文件也不至于影响到磁盘的I/O性能,缺点在于目录层次太深,对SEO稍微不 利。第二种链接格式中的y%year% 为啥要加字母前缀呢?目的是为了防止静态化之后和默认的归档链接冲突,你可以加前缀字母”y”,当然也可以是其他字母,也可以是后缀!

综上,若你是个人blog,完全可以用第一种wordpress永久链接格式,若是团队blog,考虑到今后的扩展,建议用第二种格式!

Bookmark and Share

Wordpress Rewrite / Permalink内部过程分析

This item was filled under [ wordpress tips ]

本文说明WP 对URL rewrite并生成当前请求的过程. 实际内容并不复杂, 说的比较啰嗦啦…

关于Query Vars
这是Wordpress全部代码中最重要的变量,所谓的query vars是一系列变量集合. WP通过解析URL设定query vars, 并通过分析query vars值决定显示那些文章,设定标志位等.所谓标志位是WP_Query类中一系列$is_xxx形式布尔成员变量,所有的is_xxx()形式 template tag实际上都是返回$wp_query里对应成员变量值.  举例而言,如果当前页面是单篇文章, 则p这个Query Var(以下简称变量)值不为空.(在WP类里空的query var根本不存在,而WP_Query类里如果对应name的query var没有设置,$wp_query->query_vars['varname']被填充为空值), 如果当前为搜索页, s变量值则为搜索关键字. 如果p和page两个变量都不为空值, 则当前为单篇文章分页页面, 依次类推. Query Vars在WP类($wp)里根据WP_Rewrite里的rewrite规则生成, 在WP_Query($wp_query)类里这些变量被用来建立主循环.

WP和WP_Query类里都有query_vars成员变量,键值为query vars里的varname. 具体的query vars包括’m', ‘p’, ‘posts’, ‘w’, ‘cat’, ‘withcomments’, ‘withoutcomments’, ’s’, ’search’, ‘exact’, ’sentence’, ‘debug’, ‘calendar’, ‘page’, ‘paged’, ‘more’, ‘tb’, ‘pb’, ‘author’, ‘order’, ‘orderby’, ‘year’, ‘monthnum’, ‘day’, ‘hour’, ‘minute’, ’second’, ‘name’, ‘category_name’, ‘tag’, ‘feed’, ‘author_name’, ’static’, ‘pagename’, ‘page_id’, ‘error’, ‘comments_popup’, ‘attachment’, ‘attachment_id’, ’subpost’, ’subpost_id’, ‘preview’, ‘robots’, ‘taxonomy’, ‘term’, ‘cpage’等公开变量,以及一些private变量. private变量不能由rewrite/GET等方式生成, 所以我们这里说的都指公开变量(public query vars)

准备知识:WP初始化过程:
基本过程是index.php  ->wp-blog.header.php ->wp-load.php .

通过wp-load.php 先后包含了wp-config.php, wp-setting.php,classes.php,fucntions.php query.php等文件,并建立了三个全局变量,$wp_the_query,$wp_rewrite和$wp ,分别为WP_Query,WP_Rewrite和WP类的实例,另外建立了一个$wp_query=&$wp_the_query, (之所以这样做是为了通过query_posts等方式新建自定义查询时不会损坏WP主循环,在自定义查询结束后可以调用wp_reset_query 把$wp_query还原为$wp_the-query引用). 然后,wp-blog-header执行wp()函数,并通过其调用$wp所属WP类的main方法,这个方法又调用一系列方法,但最重要的是 parse_request方法, WP从这里开始解析URL并建立主循环.

我们假设使用了友好的permalink,并且通过Apache下.htaccess实现. 那么 ,WP类的parse_request方法建立一个$request变量,这个变量值是$_SERVER['REUEST_URI'] 或$_SERVER['PATH_INFO']经过处理后的值, 是request_uri还是path_info取决于当前是否URL是否pathinfo类型请求. 处理过程包括,移除request_uri和path_info里?以后部分(即所有GET参数). 去除request url开始的/ ,  如果你WP安装在子目录(如wordpress/目录), 从(request_uri和pathinfo)开头去除wordpress/ , 去除末尾的’/’ , 对request_uri进行rawurldecode等. ($_SERVER['PATH_INFO']的值已经是decode过的了,所以无需由wp处理).当一切完成后, $request就是一个规范化的当前请求filename, 形如 post-slug, date/YYYY/mm, tag/tag-slug之类 , 接下来,WP根据rewrite规则逐条对$request进行匹配(preg_match), 如果找到一个匹配, 建立相关的变量(query vars);如果没有任何匹配,则为404

所谓的Rewrite规则就是关联数组, 键值为用来匹配$request的正则表达式, 值为解析的变量, 如’([0-9]+)(/[0-9]+)?/?$’ => ‘index.php?p=$matches[1]&page=$matches[2]‘ 就是一条规则. 具体解析过程稍后会有介绍.在WP类里会调用$wp_rewrite的wp_rewrite_rules方法获取rewrite规则.注意Rewrite 规则有缓存的, 保存在数据库wp_option表,option name为rewrite_rules.如果数据库里这个option值为空,wp_rewrite_rules()会根据你的permalink structure重新生成rewrite规则, 并保存到数据库中.在后台更改永久链接结构时也会重新生成rewrite规则并保存到数据库中.

具体的过程,举例说明,如果你使用了 /%post_id% 形式的permalink, 当前URL是 http://domain.com/18. 解析出来的$request则是18 . WP对rewrite数组里每条规则$match用preg_match(“!^$match!”, $request, $matches)语句尝试匹配, 发现$request与 ‘([0-9]+)(/[0-9]+)?/?$’ => ‘index.php?p=$matches[1]&page=$matches[2]‘ 这条规则匹配, preg_match把 ‘18′ 和空值保存到$matches数组里, 然后WP提取出匹配项值?后部分’p=$matches[1]&page=$matches[2]‘,对这个字符串$query执行 eval(“@\$query = \”" . addslashes($query) . “\”;”);语句, 这句的目的是把$matches[1]替换为18, 把 $matches[2]替换为空. 所以$query值变为’p=671&page=’, 然后执行parse_str($query, $perma_query_vars); 这样现在$perma_query_vars数组里就有键值’为p’和’page’的值.  但这还不是最终的query vars, 最终生成的query vars是$GLOBALS, $_POST, $GET和$perma_query_vars里键值为变量名项集合.依次判断. 如果 $_POST['varname']存在,则varname这个query var值为$_POST['varname'], 而不再继续判断$_GET['varname']和$perma_query_vars['varname']是否存在, 如此类推. 最后生成的query vars保存在 $wp->query_vars里.

如果使用的是默认的/?p=123 permalink形式,那么上面过程简单的多,只会从$GLOBALS, $_POST, $GET里提取query vars变量值,而不会解析REQUEST_URI和PATH_INFO.

上面过程完成后会执行parse_request这个Action,然后执行$wp的query_posts方法,这个方法 把$wp->query_vars传给$wp_the_query的query方法,开始建立主循环,设定标志位(is_home, is_page …)等.接下来就是载入模板显示页面内容了.

下面分析一些问题:
1. 假设permalink设置为/%post_id%, 数据库中有id为 10和11的两篇文章, 访问http://domain.com/10/?p=11 ,显示什么内容?- -
答案是会显示id为11的文章,因为上面说的, $_GET里变量优先级高于rewrite rules里解析出来的变量($perma_query_vars),所以最后的p变量值为11.但这时WP通常会把当前页重定向到http://domain.com/11, 因为WP有canoninol机制(wp-includes/canonical.php),能够301重定向一些不规范地址到规范url, 典型的如把其他域名重定向到后台HOME和SITEURL里设定的域名里页面.但WP的canonical机制并不完善, 个人推荐使用permalink validator插件,这个插件判断当前URL与官方URL是否完全匹配,如果不匹配要么重定向,要么set 404,..

2. 假设permalink设置为/%post_name%, 访问http://domain.com/index.php/%post_name%结果如何?
如果对应slug的post存在的话, 不会是404. 因为虽然你permalink没有设置为index.php形式的path info permalink,但如上面所说,WP在解析URL时并不判断后台设定的永久链接结构是path info还是request uri类型或者甚至是默认/?p=123类型. 不过这时通常会重定向到http://domain.com/%post_name% , 同样因为canonical机制.

3. 关于URL末尾的 ‘/’
URL末尾是否有/对rewrite没有影响, 如上所述, WP类在生成$request时会去除requset_uri和path_info末尾/ ,另外,你注意到所有WP生成的rewrite规则, 键值正则式的末尾均为  /?$ ,表示URL末尾可选 / .  不过wp会判断当前URL末尾是否有/ 以及后台设置的permalink末尾是否有/, 如果不一致则301重定向, 还是因为canonical代码. 请注意WP的 canonical代码在template_redirect这个action处执行,这时WP实际上已经解析完query vars, 主循环也设置好了, 即将载入模板..

4. 假设permalink设置为/%post_name%,数据库里两个有slug都为’about’的post和page,访问http://domain.com/about, 显示哪个?
这种情况由rewrite规则数组顺序决定, 通常wp生成的rewrite规则里 ‘(.+?)(/[0-9]+)?/?$’ => ‘index.php?pagename=$matches[1]&page=$matches[2]‘ 这条规则是最后一个, 所以这时会显示post而不是page.

5. 有人使用”古怪”的permalink结构,如/?p=%post_id%.html, 然后发现所有分类/tag页全部显示最新文章= =
原因是在这种古怪的permalink结构下,WP根本无法正确获取query vars变量,无论从GET还是url rewrite,因为如上面所说,wp rewrite 的第一步就是去除request_uri和path_info里?以后部分.事实上在这种情况下单篇文章页能够正常显示也仅仅因为有一个通过GET传递的 p变量,值为 18.html这样形式,然后php 的 (int) 或intval() 把它变成了18 = =

6 .关于Verbose rewrite
以Apache为例,wp默认生成的.htaccess里mod_rewrite规则非常简单:

  1. # BEGIN WordPress
  2. <IfModule mod_rewrite.c>
  3. RewriteEngine On
  4. RewriteBase /
  5. RewriteCond %{REQUEST_FILENAME} !-f
  6. RewriteCond %{REQUEST_FILENAME} !-d
  7. RewriteRule . /index.php [L]
  8. </IfModule>
  9. # END WordPress

复制代码

如 果当前请求不为文件或目录,把URL请求里第一个字符重写到index.php并停止继续rewrite.然后WP会通过request_uri或 path_info解析query vars, 如上面所述.  WP还提供一种non verbose rewrite rules, 但并没有提供前台接口. 在wp-include/rewrite.php里把WP_Rewrite里var $use_verbose_rules = true; 这句赋值改为false, 后台重新保存一下permalink,你会发现.htaccess里内容已经变了:

  1. # BEGIN WordPress
  2. <IfModule mod_rewrite.c>
  3. RewriteEngine On
  4. RewriteBase /
  5. RewriteCond %{REQUEST_FILENAME} -f [OR]
  6. RewriteCond %{REQUEST_FILENAME} -d
  7. RewriteRule ^robots\.txt$ /index.php?robots=1 [QSA,L]
  8. RewriteRule ^.*wp-atom.php$ /index.php?feed=atom [QSA,L]
  9. RewriteRule ^.*wp-rdf.php$ /index.php?feed=rdf [QSA,L]
  10. RewriteRule ^.*wp-rss.php$ /index.php?feed=rss [QSA,L]
  11. RewriteRule ^.*wp-rss2.php$ /index.php?feed=rss2 [QSA,L]
  12. RewriteRule ^.*wp-feed.php$ /index.php?feed=feed [QSA,L]
  13. RewriteRule ^.*wp-commentsrss2.php$ /index.php?feed=rss2&withcomments=1 [QSA,L]
  14. RewriteRule ^feed/(feed|rdf|rss|rss2|atom)/?$ /index.php?&feed=$1 [QSA,L]
  15. RewriteRule ^(feed|rdf|rss|rss2|atom)/?$ /index.php?&feed=$1 [QSA,L]
  16. …..
  17. RewriteRule ^(.+)/page/?([0-9]{1,})/?$ /index.php?pagename=$1&paged=$2 [QSA,L]
  18. RewriteRule ^(.+)/comment-page-([0-9]{1,})/?$ /index.php?pagename=$1&cpage=$2 [QSA,L]
  19. RewriteRule ^(.+)(/[0-9]+)?/?$ /index.php?pagename=$1&page=$2 [QSA,L]
  20. </IfModule>
  21. # END WordPress

你 可能对这种rewrite规则更为熟悉,国内的程序基本上都是用这种Rewrite. 请注意这时WP的内部过程完全不同. 在这种情况下, WP 的query vars值均来源于$_GET (Apache直接rewrite生成的), 但Request_uri或Path_Info仍会被解析并且生成的$perma_query_vars完全正确,! 只是不会被用于query vars而已. 因为$_GET优先级高于对url rewrite获得的值. 有人在windows下IIS的httpd.ini里加入rewrite规则,后台permalink设置为默认后rewrite后友好地址仍可以访问, 就是这个原因.

如果你能看懂(或早已知道)上面内容, 那么, 我相信对所有关于Wordpress rewrite/permalink方面的问题,你都能够解决,或者至少找到思路.至少,我是这样的.XT.

Bookmark and Share

PHOTOSHOP快捷键大全

This item was filled under [ photoshop ]

取消当前命令:Esc;
工具选项板:Enter;
选项板调整:Shift+Tab;
退出系统:Ctrl+Q;
获取帮助:F1;
剪切选择区:F2 / Ctrl+X;
拷贝选择区:F3 / Ctrl+C;
粘贴选择区:F4 / Ctrl+V;
显示或关闭画笔选项板:F5;
显示或关闭颜色选项板:F6;
显示或关闭图层选项板:F7;
显示或关闭信息选项板:F8;
显示或关闭动作选项板:F9;
显示或关闭选项板、状态栏和工具箱:Tab;
全选:Ctrl+A;
反选:Shift+Ctrl+I;
取消选择区:Ctrl+D;
选择区域移动:方向键;
将图层转换为选择区:Ctrl+单击工作图层;
选择区域以10个像素为单位移动:Shift+方向键;
复制选择区域:Alt+方向键;
填充为前景色:Alt+Delete;
填充为背景色:Ctrl+Delete;
调整色阶工具:Ctrl+L;
调整色彩平衡:Ctrl+B;
调节色调/饱和度:Ctrl+U;
自由变形:Ctrl+T;
增大笔头大小:“中括号”;
减小笔头大小:“中括号”;
选择最大笔头:Shift+“中括号”;
选择最小笔头:Shift+“中括号”;
重复使用滤镜:Ctrl+F;
移至上一图层:Ctrl+“中括号”;
排至下一图层:Ctrl+“中括号”;
移至最前图层:Shift+Ctrl+“中括号”;
移至最底图层:Shift+Ctrl+“中括号”;
激活上一图层:Alt+“中括号”;
激活下一图层:Alt+“中括号”;
合并可见图层:Shift+Ctrl+E;
放大视窗:Ctrl+“+”;
缩小视窗:Ctrl+“-”;
放大局部:Ctrl+空格键+鼠标单击;
缩小局部:Alt+空格键+鼠标单击;
翻屏查看:PageUp/PageDown;
显示或隐藏标尺:Ctrl+R;
显示或隐藏虚线:Ctrl+H;
显示或隐藏网格:Ctrl+”。
打开文件:Ctrl+O;
关闭文件:Ctrl+W;
文件存盘:Ctrl+S;
打印文件:Ctrl+P;
恢复到上一步:Ctrl+Z;

工具箱(多种工具共用一个快捷键的可同时按【Shift】加此快捷键选取)
矩形、椭圆选框工具 【M】
裁剪工具 【C】
移动工具 【V】
套索、多边形套索、磁性套索 【L】
魔棒工具 【W】
喷枪工具 【J】
画笔工具 【B】
像皮图章、图案图章 【S】
历史记录画笔工具 【Y】
像皮擦工具 【E】
铅笔、直线工具 【N】
模糊、锐化、涂抹工具 【R】
减淡、加深、海棉工具 【O】
钢笔、自由钢笔、磁性钢笔 【P】
添加锚点工具 【+】
删除锚点工具 【-】
直接选取工具 【A】
文字、文字蒙板、直排文字、直排文字蒙板 【T】
度量工具 【U】
直线渐变、径向渐变、对称渐变、角度渐变、菱形渐变 【G】
油漆桶工具 【K】
吸管、颜色取样器 【I】
抓手工具 【H】
缩放工具 【Z】
默认前景色和背景色 【D】
切换前景色和背景色 【X】
切换标准模式和快速蒙板模式 【Q】
标准屏幕模式、带有菜单栏的全屏模式、全屏模式 【F】
临时使用移动工具 【Ctrl】
临时使用吸色工具 【Alt】
临时使用抓手工具 【空格】
打开工具选项面板 【Enter】
快速输入工具选项(当前工具选项面板中至少有一个可调节数字) 【0】至【9】
循环选择画笔 【[】或【>】
选择第一个画笔 【Shift】+【[】
选择最后一个画笔 【Shift】+【>】
建立新渐变(在”渐变编辑器”中) 【Ctrl】+【N】
文件操作
新建图形文件 【Ctrl】+【N】
用默认设置创建新文件 【Ctrl】+【Alt】+【N】
打开已有的图像 【Ctrl】+【O】
打开为… 【Ctrl】+【Alt】+【O】
关闭当前图像 【Ctrl】+【W】
保存当前图像 【Ctrl】+【S】
另存为… 【Ctrl】+【Shift】+【S】
存储副本 【Ctrl】+【Alt】+【S】
页面设置 【Ctrl】+【Shift】+【P】
打印 【Ctrl】+【P】
打开“预置”对话框 【Ctrl】+【K】
显示最后一次显示的“预置”对话框 【Alt】+【Ctrl】+【K】
设置“常规”选项(在预置对话框中) 【Ctrl】+【1】
设置“存储文件”(在预置对话框中) 【Ctrl】+【2】
设置“显示和光标”(在预置对话框中) 【Ctrl】+【3】
设置“透明区域与色域”(在预置对话框中) 【Ctrl】+【4】
设置“单位与标尺”(在预置对话框中) 【Ctrl】+【5】
设置“参考线与网格”(在预置对话框中) 【Ctrl】+【6】
外发光效果(在”效果”对话框中) 【Ctrl】+【3】
内发光效果(在”效果”对话框中) 【Ctrl】+【4】
斜面和浮雕效果(在”效果”对话框中) 【Ctrl】+【5】
应用当前所选效果并使参数可调(在”效果”对话框中) 【A】
图层混合模式
循环选择混合模式 【Alt】+【-】或【+】
正常 【Ctrl】+【Alt】+【N】
阈值(位图模式) 【Ctrl】+【Alt】+【L】
溶解 【Ctrl】+【Alt】+【I】
背后 【Ctrl】+【Alt】+【Q】
清除 【Ctrl】+【Alt】+【R】
正片叠底 【Ctrl】+【Alt】+【M】
屏幕 【Ctrl】+【Alt】+【S】
叠加 【Ctrl】+【Alt】+【O】
柔光 【Ctrl】+【Alt】+【F】
强光 【Ctrl】+【Alt】+【H】
颜色减淡 【Ctrl】+【Alt】+【D】
颜色加深 【Ctrl】+【Alt】+【B】
变暗 【Ctrl】+【Alt】+【K】
变亮 【Ctrl】+【Alt】+【G】
差值 【Ctrl】+【Alt】+【E】
排除 【Ctrl】+【Alt】+【X】
色相 【Ctrl】+【Alt】+【U】
饱和度 【Ctrl】+【Alt】+【T】
颜色 【Ctrl】+【Alt】+【C】
光度 【Ctrl】+【Alt】+【Y】
去色 海棉工具+【Ctrl】+【Alt】+【J】
加色 海棉工具+【Ctrl】+【Alt】+【A】
暗调 减淡/加深工具+【Ctrl】+【Alt】+【W】
中间调 减淡/加深工具+【Ctrl】+【Alt】+【V】
高光 减淡/加深工具+【Ctrl】+【Alt】+【Z】
选择功能
全部选取 【Ctrl】+【A】
取消选择 【Ctrl】+【D】
重新选择 【Ctrl】+【Shift】+【D】
羽化选择 【Ctrl】+【Alt】+【D】
反向选择 【Ctrl】+【Shift】+【I】
路径变选区 数字键盘的【Enter】
载入选区 【Ctrl】+点按图层、路径、通道面板中的缩约图
滤镜
按上次的参数再做一次上次的滤镜 【Ctrl】+【F】
退去上次所做滤镜的效果 【Ctrl】+【Shift】+【F】
重复上次所做的滤镜(可调参数) 【Ctrl】+【Alt】+【F】
选择工具(在“3D变化”滤镜中) 【V】
立方体工具(在“3D变化”滤镜中) 【M】
球体工具(在“3D变化”滤镜中) 【N】
柱体工具(在“3D变化”滤镜中) 【C】
轨迹球(在“3D变化”滤镜中) 【R】
全景相机工具(在“3D变化”滤镜中) 【E】
视图操作
显示彩色通道 【Ctrl】+【~】
显示单色通道 【Ctrl】+【数字】
显示复合通道 【~】
以CMYK方式预览(开关) 【Ctrl】+【Y】
打开/关闭色域警告 【Ctrl】+【Shift】+【Y】
放大视图 【Ctrl】+【+】
缩小视图 【Ctrl】+【-】
满画布显示 【Ctrl】+【0】
实际象素显示 【Ctrl】+【Alt】+【0】
向上卷动一屏 【PageUp】
向下卷动一屏 【PageDown】
向左卷动一屏 【Ctrl】+【PageUp】
向右卷动一屏 【Ctrl】+【PageDown】
向上卷动10 个单位 【Shift】+【PageUp】
向下卷动10 个单位 【Shift】+【PageDown】
向左卷动10 个单位 【Shift】+【Ctrl】+【PageUp】
向右卷动10 个单位 【Shift】+【Ctrl】+【PageDown】
将视图移到左上角 【Home】
将视图移到右下角 【End】
显示/隐藏选择区域 【Ctrl】+【H】
显示/隐藏路径 【Ctrl】+【Shift】+【H】
显示/隐藏标尺 【Ctrl】+【R】
显示/隐藏参考线 【Ctrl】+【;】
显示/隐藏网格 【Ctrl】+【”】
贴紧参考线 【Ctrl】+【Shift】+【;】
锁定参考线 【Ctrl】+【Alt】+【;】
贴紧网格 【Ctrl】+【Shift】+【”】
显示/隐藏“画笔”面板 【F5】
显示/隐藏“颜色”面板 【F6】
显示/隐藏“图层”面板 【F7】
显示/隐藏“信息”面板 【F8】
显示/隐藏“动作”面板 【F9】
显示/隐藏所有命令面板 【TAB】
显示或隐藏工具箱以外的所有调板 【Shift】+【TAB】
文字处理(在”文字工具”对话框中)
左对齐或顶对齐 【Ctrl】+【Shift】+【L】
中对齐 【Ctrl】+【Shift】+【C】
右对齐或底对齐 【Ctrl】+【Shift】+【R】
左/右选择 1 个字符 【Shift】+【←】/【→】
下/上选择 1 行 【Shift】+【↑】/【↓】
选择所有字符 【Ctrl】+【A】
选择从插入点到鼠标点按点的字符 【Shift】加点按
左/右移动 1 个字符 【←】/【→】
下/上移动 1 行 【↑】/【↓】
左/右移动1个字 【Ctrl】+【←】/【→】
将所选文本的文字大小减小2 点象素 【Ctrl】+【Shift】+【
将所选文本的文字大小增大2 点象素 【Ctrl】+【Shift】+【>】
将所选文本的文字大小减小10 点象素 【Ctrl】+【Alt】+【Shift】+【
将所选文本的文字大小增大10 点象素 【Ctrl】+【Alt】+【Shift】+【>】
将行距减小2点象素 【Alt】+【↓】
将行距增大2点象素 【Alt】+【↑】
将基线位移减小2点象素 【Shift】+【Alt】+【↓】
将基线位移增加2点象素 【Shift】+【Alt】+【↑】
将字距微调或字距调整减小20/1000ems 【Alt】+【←】
将字距微调或字距调整增加20/1000ems 【Alt】+【→】
将字距微调或字距调整减小100/1000ems 【Ctrl】+【Alt】+【←】
将字距微调或字距调整增加100/1000ems 【Ctrl】+【Alt】+【→】
设置“增效工具与暂存盘”(在预置对话框中) 【Ctrl】+【7】
设置“内存与图像高速缓存”(在预置对话框中) 【Ctrl】+【8】
编辑操作
还原/重做前一步操作 【Ctrl】+【Z】
还原两步以上操作 【Ctrl】+【Alt】+【Z】
重做两步以上操作 【Ctrl】+【Shift】+【Z】
剪切选取的图像或路径 【Ctrl】+【X】或【F2】
拷贝选取的图像或路径 【Ctrl】+【C】
合并拷贝 【Ctrl】+【Shift】+【C】
将剪贴板的内容粘到当前图形中 【Ctrl】+【V】或【F4】
将剪贴板的内容粘到选框中 【Ctrl】+【Shift】+【V】
自由变换 【Ctrl】+【T】
应用自由变换(在自由变换模式下) 【Enter】
从中心或对称点开始变换 (在自由变换模式下) 【Alt】
限制(在自由变换模式下) 【Shift】
扭曲(在自由变换模式下) 【Ctrl】
取消变形(在自由变换模式下) 【Esc】
自由变换复制的象素数据 【Ctrl】+【Shift】+【T】
再次变换复制的象素数据并建立一个副本 【Ctrl】+【Shift】+【Alt】+【T】
删除选框中的图案或选取的路径 【DEL】
用背景色填充所选区域或整个图层 【Ctrl】+【BackSpace】或【Ctrl】+【Del】
用前景色填充所选区域或整个图层 【Alt】+【BackSpace】或【Alt】+【Del】
弹出“填充”对话框 【Shift】+【BackSpace】
从历史记录中填充 【Alt】+【Ctrl】+【Backspace】
图像调整
调整色阶 【Ctrl】+【L】
自动调整色阶 【Ctrl】+【Shift】+【L】
打开曲线调整对话框 【Ctrl】+【M】
在所选通道的曲线上添加新的点(‘曲线’对话框中) 在图象中【Ctrl】加点按
在复合曲线以外的所有曲线上添加新的点(‘曲线’对话框中) 【Ctrl】+【Shift】
加点按
移动所选点(‘曲线’对话框中) 【↑】/【↓】/【←】/【→】
以10点为增幅移动所选点以10点为增幅(‘曲线’对话框中) 【Shift】+【箭头】
选择多个控制点(‘曲线’对话框中) 【Shift】加点按
前移控制点(‘曲线’对话框中) 【Ctrl】+【Tab】
后移控制点(‘曲线’对话框中) 【Ctrl】+【Shift】+【Tab】
添加新的点(‘曲线’对话框中) 点按网格
删除点(‘曲线’对话框中) 【Ctrl】加点按点
取消选择所选通道上的所有点(‘曲线’对话框中) 【Ctrl】+【D】
使曲线网格更精细或更粗糙(‘曲线’对话框中) 【Alt】加点按网格
选择彩色通道(‘曲线’对话框中) 【Ctrl】+【~】
选择单色通道(‘曲线’对话框中) 【Ctrl】+【数字】
打开“色彩平衡”对话框 【Ctrl】+【B】
打开“色相/饱和度”对话框 【Ctrl】+【U】
全图调整(在色相/饱和度”对话框中) 【Ctrl】+【~】
只调整红色(在色相/饱和度”对话框中) 【Ctrl】+【1】
只调整黄色(在色相/饱和度”对话框中) 【Ctrl】+【2】
只调整绿色(在色相/饱和度”对话框中) 【Ctrl】+【3】
只调整青色(在色相/饱和度”对话框中) 【Ctrl】+【4】
只调整蓝色(在色相/饱和度”对话框中) 【Ctrl】+【5】
只调整洋红(在色相/饱和度”对话框中) 【Ctrl】+【6】
去色 【Ctrl】+【Shift】+【U】
反相 【Ctrl】+【I】
图层操作
从对话框新建一个图层 【Ctrl】+【Shift】+【N】
以默认选项建立一个新的图层 【Ctrl】+【Alt】+【Shift】+【N】
通过拷贝建立一个图层 【Ctrl】+【J】
通过剪切建立一个图层 【Ctrl】+【Shift】+【J】
与前一图层编组 【Ctrl】+【G】
取消编组 【Ctrl】+【Shift】+【G】
向下合并或合并联接图层 【Ctrl】+【E】
合并可见图层 【Ctrl】+【Shift】+【E】
盖印或盖印联接图层 【Ctrl】+【Alt】+【E】
盖印可见图层 【Ctrl】+【Alt】+【Shift】+【E】
将当前层下移一层 【Ctrl】+【[】
将当前层上移一层 【Ctrl】+【>】
将当前层移到最下面 【Ctrl】+【Shift】+【[】
将当前层移到最上面 【Ctrl】+【Shift】+【>】
激活下一个图层 【Alt】+【[】
激活上一个图层 【Alt】+【>】
激活底部图层 【Shift】+【Alt】+【[】
激活顶部图层 【Shift】+【Alt】+【>】
调整当前图层的透明度(当前工具为无数字参数的,如移动工具) 【0】至【9】
保留当前图层的透明区域(开关) 【/】
投影效果(在”效果”对话框中) 【Ctrl】+【1】
内阴影效果(在”效果”对话框中) 【Ctrl】+【2】

Bookmark and Share

urllister.py中的问题

This item was filled under [ 易懂python ]
在8.3节里,urllister.py 和 后面调用该模块的代码,不明白
urllister.py如下:

from sgmllib import SGMLParser

class URLLister(SGMLParser):
def reset(self):
SGMLParser.reset(self)
self.urls = []

def start_a(self, attrs):
href = [v for k, v in attrs if k=='href']
if href:
self.urls.extend(href)

使用代码过程:
>>> import urllib, urllister
>>> usock = urllib.urlopen(“http://diveintopython.org/”)
>>> parser = urllister.URLLister()
>>> parser.feed(usock.read())
>>> usock.close()
>>> parser.close()
>>> for url in parser.urls: print url

关于urllister.py,书中有说明:
reset 由 SGMLParser 的 __init__ 方法来调用,也可以在创建一个分析器实例时手工来调用。所以如果您需要做初始化,在 reset 中去做,而不要在 __init__ 中做。这样当某人重用一个分析器实例时,会正确地重新初始化。这部分看了sgmllib的代码,明白了

但是,后面说“只要找到一个 <a> 标记,start_a 就会由 SGMLParser 进行调用”,这个怎么也搞不懂,为什么找到<a>后就会自动调用start_a呢?怎么体现出来的?请帮忙解释一下,非常感谢

#######################################
查看sgmllib中的源码:(SGMLParser模块中)
def finish_starttag(self, tag, attrs):
try:
method = getattr(self, ’start_’ + tag)
欢迎交流,我的邮箱是ljy080829@gmail.com
Bookmark and Share
Tagged with: [ , , , ]

python 解析url

This item was filled under [ 一步一步学习中 ]

摘录了dive into python的例子

Python代码
  1. #-*-coding:utf-8-*-
  2. import HTMLParser
  3. #html解析,继承HTMLParser类
  4. class MyHTMLParser(HTMLParser.HTMLParser):
  5. def _init(self):
  6. HTMLParser.HTMLParser.__init__(self);
  7. # 处理开始标签和结束标签 – finish processing of start+end tag: <tag…/>
  8. def handle_startendtag(self, tag, attrs):
  9. self.handle_starttag(tag, attrs)
  10. self.handle_endtag(tag)
  11. #handle start tag
  12. #处理开始标签和结束标签 这里打印出a标签的href的属性值
  13. def handle_starttag(self,tag, attrs):
  14. if tag==‘a’:
  15. for name,value in attrs:
  16. if name==‘href’:
  17. print value
  18. # 处理结束标签,比如</xx> – handle end tag
  19. def handle_endtag(self,tag):
  20. pass;
  21. # 处理特殊字符串,就是以&#开头的,一般是内码表示的字符 – handle character reference
  22. def handle_charref(self, name):
  23. pass
  24. # 处理一些特殊字符,以&开头的,比如 &nbsp; – handle entity reference
  25. def handle_entityref(self, name):
  26. pass
  27. # 处理数据,就是<xx>data</xx>中间的那些数据 – handle data
  28. def handle_data(self, data):
  29. pass
  30. # 处理注释 – handle comment
  31. def handle_comment(self, data):
  32. pass
  33. # 处理<!开头的,比如<!DOCTYPE html PUBLIC ”-//W3C//DTD HTML 4.01 Transitional//EN” – handle declaration
  34. def handle_decl(self, decl):
  35. pass
  36. # 处理形如<?instruction>的东西 – handle processing instruction
  37. def handle_pi(self, data):
  38. pass
  39. a=‘<body><a href=”www.163.com”>test</a></body>’
  40. print a
  41. my=MyHTMLParser()
  42. my.feed(a)
  43. #结果为www.163.com
Bookmark and Share
Tagged with: [ ]
Page 1 of 512345»