• 2010-01-04

    变更WordPress数据库表前缀

    Views: 20984 | No Comments

    假设你原来的前缀是"wp_", 将数据库中所有表都改名一遍.

    然后修改config.php:

    $table_prefix = 'PREFIX_';

    直接修改数据库表 wp_usermeta, 将meta_key带前缀"wp_"的行, 全部修改为"PREFIX_"前缀(你的新前缀).

    直接修改数据库表 wp_options, 将option_name=wp_user_roles的那一行, 修改为option_name=PREFIX_user_roles.

    如果没有做这些修改, 会在后台管理页面遇到错误提示"You do not have sufficient permissions to access this page."或"您没有足够的权限访问本页面".

    Posted by ideawu at 2010-01-04 17:59:34 Tags:
  • 2009-12-08

    PHP中使用foreach和引用导致程序BUG

    Views: 19102 | 1 Comment

    PHP 引用有些类似 C 语言指针, 但一些重要的特性和 C 语言指针不一样, 如果不注意, 会导致程序 BUG. foreach 操作的是数组或对象的拷贝, 但 PHP5, 可以使用引用操作对象元素本身.

    $a = array(1, 2);
    $b = array(11, 12);
    foreach($a as &$r){
    }
    foreach($b as $r){
    }
    echo $a[1]; // 输出 12
    

    两个的循环的本意可能是: 第一个循环需要在循环中修改元素的内容, 所以使用引用; 但第二个循环只是把 $r 当作一个临时变量. 可是, 为什么 $a[1] 的值发生了改变呢?

    当对 $a 的迭代完成后, $r 是 $a[1] 的引用, 改变 $r 的值, 就是改变 $a[1]. 这时, 你可以会奇怪, 代码中并没有修改 $r, 也没有修改 $a[1] 呀?

    其实, foreach 是操作的是数组的拷贝, 所以, 后一个迭代相当于:

    for($i=0; $i<count($b); $i++){
    	$r = $b[$i]; // 修改了 $r! 相当于 $a[1] = $b[$i];
    }
    

    为了避免这种情况, 应该在第一个迭代之后, 执行

    unset($r);
    

    从当前环境中删除 $r 这个变量(引用变量).

    即使不是前面的例子, 在第一个迭代之后, 仍然十分可能再执行类似的语句:

    $r = 123;
    

    循环变量一般是临时变量, 同一个变量名在代码不同的地方表示不同的东西, 但变量的作用域又存在于循环之外. 这就是这种作用域规则的坏处, 加上"变量不声明即使用"的坏外, 再加上变量无类型的坏处.

    所以, 在 PHP 中使用引用变量, 应该在引用使用完之后, 应该 unset(). 所有变量在使用之前应该先 unset().

    最好是, 不到万不得已, 不要使用引用.

    Posted by ideawu at 2009-12-08 15:22:10
  • 2009-11-23

    数据库字段设计错误导致的系统BUG

    Views: 24226 | No Comments

    Yii的AR类, 可以在rules()函数中声明验证规则. 但指定了验证规则, 也可以不使用. 在调用save()方法时, 如何第一个参数为false(默认为true), 则不进行验证. 一旦验证失败, 将立即返回, 不保存数据. Yii提供的工具可以根据数据库表定义自动生成验证规则. AR类的验证规则的另一个功能是用于自动生成HTML页面表单. 但是, 根据实际使用情况, Yii所提供的这个功能在XXX项目中几乎已经成为鸡肋, 都是在开发者不知情的情况下使用了.

    Yii的这个特性, 加上数据库表设计的失误, 以及代码逻辑问题, 导致某个功能出现BUG.

    代码的功能是这样的: 调用AR类的save()方法保存一条记录, 然后跳转到该记录的详细信息页面. 实际操作时, 偶尔出现记录未保存, 然后跳转URL里的id参数为空. 代码逻辑如下:

    if($ar->save()){
        // do something
    }
    redirect($ar->id);
    

    显然, 代码逻辑没有错误处理, 无论成功与否, 都跳转. 下面再分析保存失败的原因.

    数据库表定义中, 备注字段的类型为VARCHAR(255), 如何短的字符串类型的应用范围一般很窄, 再加上所对应的业务字段是备注信息, 往往是大段的文本, 所以, 数据库设计已经失败, 出错是必然的. 另外, 程序逻辑无论是客户端还是服务器端, 都没有再做业务层的验证给出错误提示, 而是无意地使用了Yii框架的AR类的验证机制. 综合上述原因, BUG的查找花费了不少的时间.

    总结:

    1. 数据库设计

    通过对数据库表字段的仔细选择来获取性能, 对于XXX系统, 这种方式已经过时. 一般只有如下几种数据类型: 数字, 字符串(varchar), 文本(长字符串, text), 时间.

    结合 MySQL, 数字主要使用int, 像tiny int, middle int之类的整数类型, 只是节省空间考虑, 速度上反而比int类型要慢, 当数值较大时, 使用bigint. 对XXX, 除了int和bigint, 其它的整数类型都没有必要.

    对于字符串和文本类型, 如果不建立索引作为查询条件, 一般使用text, 不要使用varchar, 如果文本较长, 则使用longtext. 如果字段对应的输入框是多行文本框, 那么就没有使用varchar的必要了. 建议原则是: 不建立索引的字符串使用text, 格式化输入框(HTML编辑控件)对应的字段使用longtext, 只有建立索引的字符串才使用varchar.

    2. AR类设计

    把AR类中的rules()函数删除.

    3. 客户端验证

    在客户端也做验证, 并在出错时提示用户. 如用户输入的文本过长, 等等.

    Posted by ideawu at 2009-11-23 16:58:12 Tags:
  • 2009-08-12

    Apach整合PHP指定php.ini路径

    Views: 24532 | No Comments

    AddType application/x-httpd-php .php
    LoadModule php5_module D:/php5.2.5/php5apache2_2.dll
    phpinidir D:/php5.2.5/

    Posted by ideawu at 2009-08-12 12:21:24 Tags:
  • 2009-08-11

    PHP字符串==比较的副作用

    Views: 14343 | No Comments
    $a = '212345678912000005';
    $b = '212345678912000001';
    var_dump($a == $b);
    

    这段代码的输出是bool(true), 说明这样判断会得出结论是两者相等. 类似的特性在in_array()函数第3个参数为false或者不设置的情况. 原因是首先判断字符串是否是数字, 然后转换成long或者double(C语言数据类型)再判断 - 使用zendi_smart_strcmp. 但是, 源码中的注释说声明考虑了溢出的情况,

    } else if (dval1 == dval2 && !zend_finite(dval1)) {
    	/* Both values overflowed and have the same sign,
    	 * so a numeric comparison would be inaccurate */
    	goto string_cmp;
    }
    

    dval1和dval2分别是两个字符串转换为double型后的值. 但为什么还是这样呢? 也许这个判断并不正确. 进一步研究再说...

    解决方法, 使用三个等号"==="代替两个等号"==", in_array()函数设置第三个参数为true: in_array('val', $array, true).

    Posted by ideawu at 2009-08-11 14:15:37
  • 2009-06-25

    单独编译一个PHP模块

    Views: 16464 | No Comments

    以libcurl为例. 执行:

    cd 源码目录/ext/curl
    执行 PHP安装目录/bin/phpize
    ./configure --with-php-config=PHP安装目录/bin/php-config
    make
    

    得到 ./modules/curl.so
    拷贝到 PHP 的模块目录
    修改 php.ini

    extension_dir = ".so文件的路径"
    extension=curl.so
    

    重启 Apache

    注意: 如果有其它版本的 /usr/local/bin/php-config 存在, 会导致编译出错. 因为这是其它版本的的环境配置, configure时会用到. 不知道怎么让configure不使用, 只能把这个文件移到别处, 编译完后再弄回来.

    Posted by ideawu at 2009-06-25 11:56:46
|<<<2345678910>>>| 6/10 Pages, 55 Results.